Auf eine Frage an Java an der Universität gab es diesen Codeausschnitt:
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();
}
}
}
Ich wurde gebeten, seine Ausgabe zu geben. Ich antwortete 13Exception in thread main MyExc2
, aber die richtige Antwort ist 132Exception in thread main MyExc1
. Warum ist es das? Ich kann einfach nicht verstehen, wohin es MyExc2
geht.
Dies ist, was Wikipedia über die Klausel finally sagt:
Lassen Sie uns Ihr Programm analysieren.
So
1
wird der Ausgang in den Bildschirm sein, dannq()
aufgerufen wird. Inq()
wird eine Ausnahme ausgelöst. Die Ausnahme wird dann abgefangenException y
, tut aber nichts. Eine finally- Klausel wird dann ausgeführt (muss) und3
wird auf dem Bildschirm gedruckt. Da (in der Methode wirdq()
in der finally- Klausel eine Ausnahme ausgelöst ,q()
übergibt auch die Methode die Ausnahme an den übergeordneten Stapel (durch diethrows Exception
in der Methodendeklaration)new Exception()
wird ausgelöst und abgefangencatch ( Exception i )
,MyExc2
wird eine Ausnahme ausgelöst (fügen Sie sie zunächst dem Ausnahmestapel hinzu ), aber ein final in themain
block wird zuerst ausgeführt.Also rein,
Eine finally- Klausel heißt im Wesentlichen ... (denken Sie daran, wir haben sie gerade gefangen
Exception i
und geworfenMyExc2
),2
wird auf dem Bildschirm gedruckt ... und nachdem die Klausel auf dem Bildschirm2
gedruckt wurde, wird eineMyExc1
Ausnahme ausgelöst.MyExc1
wird von derpublic static void main(...)
Methode behandelt.Ausgabe:
Dozent ist richtig! :-)
Wenn Sie eine finally / catch-Klausel haben, wird im Wesentlichen eine finally- Klausel ausgeführt ( nachdem Sie die Ausnahme abgefangen haben, bevor Sie die abgefangene Ausnahme ausgelöst haben).
quelle
catch
wird ausgeführt, daq()
einException
aus einem eigenenfinally
Block geworfen wurde.q
übergibt die Ausführung an die leerercatch
Block inq
(der diese Ausnahme verschluckt), dann zumfinally
Block inq
. Said blockiert schließlich Drucke3
und löst dann eine neue Ausnahme aus, die dankq
'sthrows Exception
den Stapel an das übergeordnete Element weitergibt.Ausnahmen im finally-Block ersetzen Ausnahmen im catch-Block.
Zitat aus der Java Language Specification 14 Edition :
quelle
Schließlich wird die Klausel auch dann ausgeführt, wenn eine Ausnahme von einer beliebigen Stelle im try / catch-Block ausgelöst wird.
Da es das letzte ist, das in ausgeführt wird,
main
und eine Ausnahme ausgelöst wird, ist dies die Ausnahme, die die Anrufer sehen.Daher ist es wichtig sicherzustellen, dass die
finally
Klausel nichts auslöst, da sie Ausnahmen aus demtry
Block verschlucken kann .quelle
A
method
kann nichtthrow
zwei Ausnahmen gleichzeitig. Es wird immer der zuletzt geworfene geworfenexception
, in diesem Fall immer der aus demfinally
Block.Wenn die erste Ausnahme von der Methode
q()
ausgelöst wird, wird sie abgefangen und dann von der endgültig blockierten Ausnahme ausgelöst.q () -> geworfen
new Exception
->main
catch Exception
->throw
new Exception
->finally
einen neuen werfenexception
(und der von dercatch
ist "verloren")quelle
Am einfachsten ist es, sich vorzustellen, dass die gesamte Anwendung eine globale Variable enthält, die die aktuelle Ausnahme enthält.
Wenn jede Ausnahme ausgelöst wird, wird "currentException" auf diese Ausnahme gesetzt. Wenn die Anwendung endet und currentException! = Null ist, meldet die Laufzeit den Fehler.
Außerdem werden die finally-Blöcke immer ausgeführt, bevor die Methode beendet wird. Sie können dann das Code-Snippet anfordern, um:
Die Reihenfolge, in der die Anwendung ausgeführt wird, lautet:
quelle
Es ist bekannt, dass der finally-Block nach dem try and catch ausgeführt wird und immer ausgeführt wird. Aber wie Sie gesehen haben, ist es manchmal etwas schwierig, sich das folgende Code-Snippet anzusehen, und Sie werden feststellen, dass die return- und throw-Anweisungen nicht funktionieren Tun Sie nicht immer das, was sie tun sollen, in der Reihenfolge, in der wir das Thema erwarten.
Prost.
quelle
Auftrag:
https://www.compilejava.net/
quelle
Die Logik ist klar, bis der Ausdruck abgeschlossen ist
13
. Dann geworfen die Ausnahme inq()
gefangen voncatch (Exception i)
inmain()
undnew MyEx2()
bereit ist , geworfen zu werden. Vor dem Auslösen der Ausnahme muss derfinally
Block jedoch zuerst ausgeführt werden. Dann wird die Ausgabe132
undfinally
fordert auf, eine weitere Ausnahme auszulösennew MyEx1()
.Da eine Methode nicht mehr als eine werfen kann
Exception
, wird immer die neueste ausgelöstException
. Mit anderen Worten, wenn beidecatch
undfinally
Blöcke versuchen zu werfenException
, wird derException
In-Catch verschluckt und nur die Ausnahme infinally
wird geworfen.Daher wird in diesem Programm die Ausnahme
MyEx2
verschluckt undMyEx1
ausgelöst. Diese Ausnahme wird verworfenmain()
und nicht mehr abgefangen, daher stoppt JVM und die endgültige Ausgabe ist132Exception in thread main MyExc1
.Im Wesentlichen , wenn Sie eine haben
finally
in einertry/catch
Klausel, einefinally
wird ausgeführt, nach dem Fang der Ausnahme , aber VOR jeder abgefangene Ausnahme zu werfen , und nur die neueste Ausnahme wäre am Ende geworfen werden .quelle
Ich denke, Sie müssen nur die
finally
Blöcke gehen:finally
imq
Druck "3".finally
immain
Druck "2".quelle
Um diese Art von Situation zu behandeln, dh die durch finally block ausgelöste Ausnahme zu behandeln. Sie können den finally-Block mit try block umgeben: Sehen Sie sich das folgende Beispiel in Python an:
quelle
Ich denke das löst das Problem:
quelle