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(String[] 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 bonne réponse est 132Exception in thread main MyExc1
. Qu'est-ce que c'est? Je ne peux tout simplement pas comprendre où va MyExc2.
Après avoir lu votre réponse et vu comment vous l’avez probablement élaborée, je pense que vous pensez qu’une "exception en cours" a "priorité". Garder en tete:
Quand une nouvelle exception est levée dans un bloc catch ou un bloc finally qui se propagera hors de ce bloc, l'exception en cours sera annulée (et oublié) lorsque la nouvelle exception est propagée vers l'extérieur. La nouvelle exception commence à dérouler la pile, comme toute autre exception, en abandonnant le bloc en cours (le bloc catch ou finally) et est soumise à toute capture ou tout bloc final le long du bloc. manière.
Notez que la capture applicable ou enfin les blocs incluent:
Quand une nouvelle exception est levée dans un bloc catch, la nouvelle exception est toujours sujette à son dernier bloc, le cas échéant.
Maintenant, retracez l’exécution en vous rappelant que chaque fois que vous appuyez sur throw
, vous devez abandonner le suivi de l’exception en cours et commencer à le suivre.
C'est ce que Wikipedia dit à propos de finally clause:
Plus commun est une clause associée (enfin, à assurer) qui est exécutée, qu’une exception se produise 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();
}
Ainsi, 1
Sera affiché à l'écran, puis q()
sera appelé. Dans q()
, une exception est levée. L'exception est alors interceptée par Exception y
Mais ne fait rien. Une clause enfin est alors exécutée (il le doit), ainsi, 3
Sera imprimé à l'écran. Parce que (dans la méthode q()
il y a une exception levée dans la clause finally, aussi la méthode q()
passe l’exception à la pile parent (par la commande throws Exception
Dans la déclaration de méthode) new Exception()
sera levé et attrapé par catch ( Exception i )
, une exception MyExc2
Sera levée (pour l'instant, ajoutez-la à la pile d'exceptions) , mais a enfin dans le bloc main
sera exécuté en premier.
Alors dans,
catch ( Exception i ) {
throw( new MyExc2() );
}
finally {
System.out.print(2);
throw( new MyExc1() );
}
Une clause finally est appelée ... (rappelez-vous, nous avons attrapé Exception i
Et jeté MyExc2
) Dans Essentiellement, 2
est imprimé à l'écran ... et une fois que 2
est imprimé à l'écran, une exception MyExc1
est levée. MyExc1
Est géré par la méthode public static void main(...)
.
Sortie:
"132Exception dans le thread principal MyExc1"
Le conférencier a raison! :-)
Essentiellement, si vous avez un enfin dans une clause try/catch, un enfin sera exécuté ( après attraper l'exception avant jeter l'exception capturée)
Citant le JLS 11: 14.20.2. Exécution de try-finally et try-catch-finally
Si le bloc catch se termine brusquement pour la raison R, le bloc finally est exécuté. Alors il y a un choix:
Si le bloc finally se termine normalement, l'instruction try se termine brutalement pour la raison R.
Si le bloc finally s'achève abruptement pour la raison S, l'instruction try s'achève abruptement pour la raison S (et la raison R est ignorée).
La clause Finally est exécutée même si une exception est levée de n'importe où dans le bloc try/catch.
Parce que c'est le dernier à être exécuté dans 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 jette rien, car elle peut avaler des exceptions du bloc try
.
Un method
ne peut pas throw
deux exceptions en même temps. Il lancera toujours le dernier lancé exception
, qui dans ce cas sera toujours celui du bloc finally
.
Lorsque la première exception à la méthode q()
est levée, elle est attrapée puis avalée par l'exception du bloc final.
q () -> jeté new Exception
->main
catch Exception
->throw
new Exception
->finally
lance un nouveau exception
(et celui du catch
est "perdu")
La façon la plus simple d’y penser est d’imaginer qu’il existe une variable globale à l’ensemble de l’application qui contient l’exception en cours.
Exception currentException = null;
A chaque exception 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 pouvez ensuite demander à l'extrait de code de:
public class C1 {
public static void main(String [] 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 dernier bloc est exécuté après le try and catch et qu'il est toujours exécuté .... Mais comme vous l'avez vu, il est parfois un peu délicat de consulter l'extrait de code ci-dessous et vous ferez en sorte que ne faites pas toujours ce qu’ils devraient faire dans l’ordre dans lequel nous nous attendons à thème.
À 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!";
}
//////////////////////////////////////////////////
class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}
public class C1 {
public static void main(String[] 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();
}
}
Ordre:
TryA L1
TryA L2
Catch L2
Finally L2
Catch L1
Finally L1
Exception in thread "main" MyExc1 at C1.main(C1.Java:30)
La logique est claire jusqu'à la fin de l'impression de 13
. Ensuite, l'exception levée dans q()
est interceptée par catch (Exception i)
dans main()
et une new MyEx2()
est prête à être levée. Cependant, avant de lancer l'exception, le bloc finally
doit d'abord être exécuté. La sortie devient alors 132
Et finally
demande de lever une autre exception new MyEx1()
.
Comme une méthode ne peut pas lancer plus d'un Exception
, elle lancera toujours le dernier Exception
. En d’autres termes, si les deux blocs catch
et finally
essaient de lancer Exception
, alors le Exception
dans la capture est avalé et seule l'exception dans finally
sera levée.
Ainsi, dans ce programme, l'exception MyEx2
Est avalée et MyEx1
Est levée. Cette exception est rejetée de main()
et n'est plus interceptée. JVM s'arrête donc et la sortie finale est 132Exception in thread main MyExc1
.
En substance, si vous avez finally
dans une clause try/catch
, Un finally
sera exécuté APRÈS avoir intercepté l'exception, mais AVANT de lancer une exception interceptée, et SEULE la dernière exception serait levée à la fin .
Pour gérer ce type de situation, c’est-à-dire gérer l’exception déclenchée par finally. Vous pouvez entourer le bloc finally par bloc try: Regardez l'exemple ci-dessous en python:
try:
fh = open("testfile", "w")
try:
fh.write("This is my test file for exception handling!!")
finally:
print "Going to close the file"
fh.close()
except IOError:
print "Error: can\'t find file or read data"
Je pense qu'il vous suffit de parcourir les blocs finally
:
finally
dans q
print "3".finally
dans main
print "2".