Cela peut sembler une question de programmation 101 et je pensais connaître la réponse, mais je me trouve maintenant dans l'obligation de vérifier. Dans cette partie de code ci-dessous, l'exception levée dans le premier bloc catch sera-t-elle interceptée par le bloc catch général Exception ci-dessous?
try {
// Do something
} catch(IOException e) {
throw new ApplicationException("Problem connecting to server");
} catch(Exception e) {
// Will the ApplicationException be caught here?
}
J'ai toujours pensé que la réponse serait non, mais maintenant j'ai un comportement étrange qui pourrait être causé par cela. La réponse est probablement la même pour la plupart des langues, mais je travaille en Java.
Non, car le nouveau throw
ne se trouve pas directement dans le bloc try
.
Non, c'est très facile à vérifier.
public class Catch {
public static void main(String[] args) {
try {
throw new Java.io.IOException();
} catch (Java.io.IOException exc) {
System.err.println("In catch IOException: "+exc.getClass());
throw new RuntimeException();
} catch (Exception exc) {
System.err.println("In catch Exception: "+exc.getClass());
} finally {
System.err.println("In finally");
}
}
}
Devrait imprimer:
Dans catch IOException: classe Java.io.IOException In Enfin Exception dans le thread "principal" Java.lang.RuntimeException À Catch.main (Catch. Java: 8)
Techniquement, cela aurait pu être un bogue du compilateur, un comportement dépendant de la mise en œuvre, non spécifié, ou quelque chose du genre. Cependant, le JLS est assez bien établi et les compilateurs sont assez bons pour ce genre de choses simples (le cas des génériques peut être différent).
Notez également que si vous permutez les deux blocs catch, la compilation n’est pas effectuée. La deuxième capture serait complètement inaccessible.
Notez que le bloc finally s'exécute toujours, même si un bloc catch est exécuté (autres que les cas idiots, tels que des boucles infinies, la liaison via l'interface des outils et la suppression du thread, la réécriture du bytecode, etc.).
La spécification de langage Java indique à la section 14.19.1:
Si l'exécution du bloc try se termine brusquement à cause d'un rejet d'une valeur V, vous avez le choix:
- Si le type d'exécution de V est assignable au paramètre de toute clause catch de l'instruction try, la première (la plus à gauche) de cette clause catch est sélectionnée. La valeur V est affectée au paramètre de la clause catch sélectionnée et le bloc de cette clause catch est exécuté. Si ce bloc se termine normalement, l'instruction try se termine normalement; si ce bloc se termine brusquement pour une raison quelconque, l'instruction try se termine brusquement pour la même raison.
Référence: http://Java.Sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134
En d’autres termes, la première capture englobante capable de gérer l’exception le fait, et si une exception est renvoyée de cette capture, elle n’entre pas dans la portée de toute autre capture de l’essai d’origine, de sorte qu’ils ne tenteront pas de la gérer.
Une chose liée et déroutante à savoir est que, dans une structure try- [catch] -finally, un bloc finally peut générer une exception et, le cas échéant, toute exception levée par le bloc try ou catch est perdue. Cela peut être déroutant la première fois que vous le voyez.
Si vous voulez lever une exception du bloc catch, vous devez informer votre méthode/classe/etc. qu'il faut jeter cette exception. Ainsi:
public void doStuff() throws MyException {
try {
//Stuff
} catch(StuffException e) {
throw new MyException();
}
}
Et maintenant, votre compilateur ne va pas vous crier dessus :)
Non - Comme l'a dit Chris Jester-Young, cela sera reporté à la prochaine tentative dans la hiérarchie.
Comme dit ci-dessus ...
J'ajouterais que si vous avez du mal à voir ce qui se passe, si vous ne pouvez pas reproduire le problème dans le débogueur, vous pouvez ajouter une trace avant de relancer la nouvelle exception (avec le bon vieux système. out.println au pire, avec un bon système de journalisation comme log4j sinon).
Il ne sera pas attrapé par le deuxième bloc catch. Chaque exception n'est interceptée que dans un bloc try. Vous pouvez faire un nid d'essais (ce n'est pas une bonne idée en général):
try {
doSomething();
} catch (IOException) {
try {
doSomething();
} catch (IOException e) {
throw new ApplicationException("Failed twice at doSomething" +
e.toString());
}
} catch (Exception e) {
}
Non, puisque les captures se rapportent toutes au même bloc try, de sorte que le lancer depuis un bloc catch serait capturé par un bloc try inclus (probablement dans la méthode qui a appelé celui-ci).