Exception lancée dans catch et enfin clause

Sur une question pour Java à l’université, il y avait cet extrait de code:

class MyExc1 extends Exception {} class MyExc2 extends Exception {} class MyExc3 extends MyExc2 {} public class C1 { public static void main(Ssortingng[] args) throws Exception { try { System.out.print(1); q(); } catch (Exception i) { throw new MyExc2(); } finally { System.out.print(2); throw new MyExc1(); } } static void q() throws Exception { try { throw new MyExc1(); } catch (Exception y) { } finally { System.out.print(3); throw new Exception(); } } } 

On m’a demandé de donner sa sortie. J’ai répondu 13Exception in thread main MyExc2 , mais la réponse correcte est 132Exception in thread main MyExc1 . Qu’est-ce que c’est? Je n’arrive pas à comprendre où va MyExc2.

En lisant votre réponse et en voyant comment vous l’avez probablement trouvée, je pense que vous pensez qu’une “exception en cours” a “préséance”. Garder en tete:

Lorsqu’une nouvelle exception est lancée dans un bloc catch ou bloc finale qui se propage hors de ce bloc, l’exception en cours sera annulée (et oubliée) lorsque la nouvelle exception sera propagée vers l’extérieur. La nouvelle exception commence à dérouler la stack comme toute autre exception, abandonnant le bloc actuel (le bloc catch ou finally) et soumis à tout bloc catch ou finalement en cours de route.

Notez que les blocs catch ou finally incluent:

Lorsqu’une nouvelle exception est lancée dans un bloc catch, la nouvelle exception est toujours soumise au blocage final de catch, le cas échéant.

Maintenant, retracez l’exécution en vous rappelant que chaque fois que vous appuyez sur throw , vous devez interrompre le suivi de l’exception en cours et commencer à tracer la nouvelle exception.

Voici ce que Wikipedia dit à propos de la clause finalement:

Plus commun est une clause associée (enfin, ou assurer) qui est exécutée qu’une exception se soit produite ou non, généralement pour libérer les ressources acquises dans le corps du bloc de gestion des exceptions.

Disséquons votre programme.

 try { System.out.print(1); q(); } 

Donc, 1 sera affiché à l’écran, alors q() est appelé. Dans q() , une exception est levée. L’exception est ensuite interceptée par Exception y mais elle ne fait rien. Une clause finally est alors exécutée (elle doit), donc 3 sera imprimée à l’écran. Parce que (dans la méthode q() il y a une exception lancée dans la clause finally , la méthode q() transmet également l’exception à la stack parente (par l’ throws Exception dans la déclaration de la méthode), new Exception() sera lancée et catch ( Exception i ) , MyExc2 exception MyExc2 sera lancée (pour l’append maintenant à la stack des exceptions), mais une enfin dans le bloc main sera exécutée en premier.

Donc, dans

 catch ( Exception i ) { throw( new MyExc2() ); } finally { System.out.print(2); throw( new MyExc1() ); } 

Une clause finally est appelée … (rappelez-vous que nous venons de capturer Exception i et que MyExc2 été MyExc2 ), 2 est imprimé à l’écran … et après que le 2 soit imprimé à l’écran, une exception MyExc1 est MyExc1 . MyExc1 est géré par la méthode public static void main(...) .

Sortie:

“132Exception dans le thread principal MyExc1”

Maître de conférences est correct! 🙂

Essentiellement , si vous avez une clause finalement dans try / catch, un finalement sera exécuté ( après avoir capturé l’exception avant de lancer l’exception).

Citant le JLS 9: 14.20.2. Exécution de try-finally et try-catch-finally

Si le bloc catch se termine brusquement pour la raison R, alors le bloc finally est exécuté. Alors il y a un choix:

  • Si le bloc finally se termine normalement, l’instruction try se termine brusquement pour la raison R.

  • Si le bloc finally se termine brusquement pour la raison S, l’instruction try se termine brusquement pour la raison S (et la raison R est ignorée).

Finalement, la clause est exécutée même si une exception est lancée de n’importe où dans le bloc try / catch.

Parce que c’est le dernier à être exécuté dans la main et qu’il lève une exception, c’est l’exception que les appelants voient.

D’où l’importance de s’assurer que la clause finally ne lance rien, car elle peut avaler des exceptions du bloc try .

Une method ne peut pas throw deux exceptions en même temps. Il lancera toujours la dernière exception renvoyée, qui dans ce cas sera toujours celle du bloc finally .

Lorsque la première exception de la méthode q() est lancée, elle sera interceptée puis avalée par l’exception finalement bloquée.

q () -> new Exception levée -> new Exception main catch Exception -> throw new Exception -> finally lancer une nouvelle exception (et celle de la catch est “perdue”)

La manière la plus simple de penser à ceci est d’imaginer qu’il existe une variable globale pour l’ensemble de l’application qui contient l’exception actuelle.

 Exception currentException = null; 

Comme chaque exception est levée, “currentException” est défini sur cette exception. Lorsque l’application se termine, si currentException est! = Null, le moteur d’exécution signale l’erreur.

De plus, les blocs finally sont toujours exécutés avant la fin de la méthode. Vous pourriez alors exiger l’extrait de code pour:

 public class C1 { public static void main(Ssortingng [] argv) throws Exception { try { System.out.print(1); q(); } catch ( Exception i ) { // <-- currentException = Exception, as thrown by q()'s finally block throw( new MyExc2() ); // <-- currentException = MyExc2 } finally { // <-- currentException = MyExc2, thrown from main()'s catch block System.out.print(2); throw( new MyExc1() ); // <-- currentException = MyExc1 } } // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console. static void q() throws Exception { try { throw( new MyExc1() ); // <-- currentException = MyExc1 } catch( Exception y ) { // <-- currentException = null, because the exception is caught and not rethrown } finally { System.out.print(3); throw( new Exception() ); // <-- currentException = Exception } } } 

L'ordre d'exécution de l'application est le suivant:

 main() { try q() { try catch finally } catch finally } 

Il est bien connu que le bloc finally est exécuté après l’essai et s’exécute toujours. Mais comme vous l’avez vu, c’est un peu délicat de vérifier ces extraits de code ci-dessous et vous verrez que les instructions return et throw Ne faites pas toujours ce qu’ils doivent faire dans l’ordre auquel nous nous attendons.

À votre santé.

 /////////////Return dont always return/////// try{ return "In Try"; } finally{ return "In Finally"; } //////////////////////////////////////////// //////////////////////////////////////////// while(true) { try { return "In try"; } finally{ break; } } return "Out of try"; /////////////////////////////////////////// /////////////////////////////////////////////////// while (true) { try { return "In try"; } finally { continue; } } ////////////////////////////////////////////////// /////////////////Throw dont always throw///////// try { throw new RuntimeException(); } finally { return "Ouuuups no throw!"; } ////////////////////////////////////////////////// 

Je pense qu’il suffit de marcher sur les finally blocs:

  1. Imprimer “1”.
  2. finally en q imprimer “3”.
  3. finally dans main impression main “2”.
 class MyExc1 extends Exception {} class MyExc2 extends Exception {} class MyExc3 extends MyExc2 {} public class C1 { public static void main(Ssortingng[] args) throws Exception { try { System.out.print("TryA L1\n"); q(); System.out.print("TryB L1\n"); } catch (Exception i) { System.out.print("Catch L1\n"); } finally { System.out.print("Finally L1\n"); throw new MyExc1(); } } static void q() throws Exception { try { System.out.print("TryA L2\n"); q2(); System.out.print("TryB L2\n"); } catch (Exception y) { System.out.print("Catch L2\n"); throw new MyExc2(); } finally { System.out.print("Finally L2\n"); throw new Exception(); } } static void q2() throws Exception { throw new MyExc1(); } } 

Commande:

 TryA L1 TryA L2 Catch L2 Finally L2 Catch L1 Finally L1 Exception in thread "main" MyExc1 at C1.main(C1.java:30) 

https://www.comstackjava.net/

Je pense que cela résout le problème:

 boolean allOk = false; try{ q(); allOk = true; } finally { try { is.close(); } catch (Exception e) { if(allOk) { throw new SomeException(e); } } }