Java Language Prendre une exception avec try-catch


Exemple

Une exception peut être interceptée et gérée à l'aide de l'instruction try...catch . (En fait, les instructions try prennent d'autres formes, comme décrit dans d'autres exemples sur try...catch...finally et try-with-resources .)

Attrapez avec un bloc catch

La forme la plus simple ressemble à ceci:

try {
    doSomething();
} catch (SomeException e) {
    handle(e);
}
// next statement

Le comportement d'une simple try...catch est le suivant:

  • Les instructions du bloc try sont exécutées.
  • Si aucune exception n'est levée par les instructions du bloc try , le contrôle passe à l'instruction suivante après le try...catch .
  • Si une exception est lancée dans le bloc try .
    • L'objet exception est testé pour voir s'il s'agit d'une instance de SomeException ou d'un sous-type.
    • S'il est, le catch bloc va attraper l'exception:
      • La variable e est liée à l'objet exception.
      • Le code dans le bloc catch est exécuté.
      • Si ce code renvoie une exception, l'exception nouvellement renvoyée est propagée à la place de celle d'origine.
      • Sinon, le contrôle passe à l'instruction suivante après le try...catch .
    • Si ce n'est pas le cas, l'exception d'origine continue à se propager.

Prise d'essai avec plusieurs prises

Un try...catch peut aussi avoir plusieurs blocs de catch . Par exemple:

try {
    doSomething();
} catch (SomeException e) {
    handleOneWay(e)
} catch (SomeOtherException e) {
    handleAnotherWay(e);
}
// next statement

S'il y a plusieurs blocs catch , ils sont essayés un à la fois en commençant par le premier, jusqu'à ce qu'une correspondance soit trouvée pour l'exception. Le gestionnaire correspondant est exécuté (comme ci-dessus), puis le contrôle est transmis à l'instruction suivante après l'instruction try...catch . Les blocs catch après celui qui correspond sont toujours ignorés, même si le code du gestionnaire renvoie une exception .

La stratégie d'appariement «descendante» a des conséquences dans les cas où les exceptions dans les blocs de catch ne sont pas disjointes. Par exemple:

try {
    throw new RuntimeException("test");
} catch (Exception e) {
    System.out.println("Exception");
} catch (RuntimeException e) {
    System.out.println("RuntimeException");
}

Cet extrait de code affichera "Exception" plutôt que "RuntimeException". Puisque RuntimeException est un sous-type d' Exception , le premier catch (plus général) sera mis en correspondance. La seconde catch (plus spécifique) ne sera jamais exécutée.

La leçon à en tirer est que les blocs de catch les plus spécifiques (en termes de types d'exception) devraient apparaître en premier et les plus généraux en dernier. (Certains compilateurs Java vous avertiront si un catch ne peut jamais être exécuté, mais ce n’est pas une erreur de compilation.)

Blocs d'interception multi-exception

Java SE 7

À partir de Java SE 7, un bloc catch unique peut gérer une liste d'exceptions non associées. Le type d'exception est répertorié, séparé par un symbole de barre verticale ( | ). Par exemple:

try {
    doSomething();
} catch (SomeException | SomeOtherException e) {
    handleSomeException(e);
} 

Le comportement d'une capture multi-exception est une simple extension pour le cas à exception unique. Le catch correspond si l'exception levée correspond (au moins) à l'une des exceptions répertoriées.

Il y a une subtilité supplémentaire dans la spécification. Le type de e est une union synthétique des types d'exception de la liste. Lorsque la valeur de e est utilisée, son type statique est le supertype le moins commun de la union de type. Toutefois, si e est renvoyé dans le bloc catch , les types d'exception levés sont les types de l'union. Par exemple:

public void method() throws IOException, SQLException
    try {
        doSomething();
    } catch (IOException | SQLException e) {
        report(e);
        throw e;
    }

Dans ce qui précède, IOException et SQLException sont des exceptions vérifiées dont le supertype le moins commun est Exception . Cela signifie que la méthode de report doit correspondre au report(Exception) . Cependant, le compilateur sait que le throw ne peut lancer qu’une SQLException IOException ou une SQLException . Ainsi, la method peut être déclarée en tant que throws IOException, SQLException plutôt que throws Exception . (Ce qui est une bonne chose: voir Pitfall - Throwable, Exception, Error ou RuntimeException .)