Es gibt 3 Permutationen eines Versuchs ... fangen ... endlich in Java blockieren.
- versuche ... zu fangen
- versuche ... endlich zu fangen
- versuche ... endlich
Sobald der finally-Block ausgeführt wurde, geht die Steuerung zur nächsten Zeile nach dem finally-Block. Wenn ich den finally-Block entferne und alle seine Anweisungen nach dem try ... catch-Block in die Zeile verschiebe, hat dies den gleichen Effekt wie sie im finally-Block?
java
exception-handling
Amit Kumar Gupta
quelle
quelle
Antworten:
Ich denke, Willenscode kommt dem Ausdruck des Schlüsselpunkts hier am nächsten, und wahrscheinlich meint es jeder, ist aber nicht klar.
Das Problem ist, dass tatsächlich etwas sehr falsch mit dem ist, was Sie fragen: "Wenn ich alle Anweisungen nach dem catch-Block schreibe, anstatt sie in den finally-Block zu schreiben, dann stimmt dann etwas nicht?"
Wenn Sie alle Anweisungen nach dem catch-Block schreiben, implizieren Sie dies
1) Sie werden immer die Ausnahme abfangen.
2) Sie fahren immer mit den nächsten Anweisungen fort, nachdem Sie die Ausnahme abgefangen haben.
Dies bedeutet, dass Sie die Ausführung nach einer Ausnahme immer "normal" fortsetzen, was im Allgemeinen etwas ist, was Sie eigentlich nie tun möchten.
Ausnahmen sollten genau das sein - außergewöhnlich. Wenn Sie tatsächlich eine Ausnahme behandeln können, ist es immer besser, Ihren Code zu schreiben, um diese Bedingungen zuerst zu berücksichtigen und überhaupt nicht zu einer Ausnahme zu führen. Wenn Sie diesem Modell folgen, sind Ausnahmen wirklich außergewöhnlich - Bedingungen, die Sie nicht vorhersehen oder höchstens nicht beheben konnten. Wirklich nicht vorwegzunehmen ist, worauf Sie hinarbeiten sollten. Dies bedeutet im Allgemeinen, dass Sie keine echten Ausnahmen verarbeiten können. Dies bedeutet auch, dass Sie die Ausführung nicht einfach fortsetzen sollten, sondern häufig die Anwendung beenden.
Normalerweise wird zugelassen, dass ein Fehler den Aufrufstapel wieder weitergibt. Einige sagen, dass dies mit der Möglichkeit geschieht, dass jemand weiter oben in der Kette damit umgehen kann. Ich würde sagen, dass im Wesentlichen nie passiert, es gibt zwei wirkliche Zwecke, um dies zu tun. Zum einen kann der Benutzer dies beheben, falls es eines gibt. Sie geben den Fehler also wieder weiter, bis Sie dort sind, wo Sie ihn dem Benutzer melden können. Oder zweitens kann ein Benutzer das Problem nicht beheben, aber Sie möchten den gesamten Aufrufstapel zum Debuggen abrufen. Dann fangen Sie es oben, um anmutig zu scheitern.
Der finally-Block sollte jetzt mehr Bedeutung für Sie haben. Wie jeder sagt, läuft es immer. Die klarste Verwendung eines Endlich ist wirklich ein Versuch ... Endlich zu blockieren. Was Sie jetzt sagen, ist, wenn der Code gut läuft, großartig. Wir müssen noch etwas aufräumen und das wird schließlich immer ausgeführt, dann gehen wir weiter. Aber wenn eine Ausnahme auftritt, brauchen wir diesen endgültigen Block jetzt wirklich, da wir möglicherweise noch einige Aufräumarbeiten durchführen müssen, aber wir fangen die Ausnahme hier nicht mehr ab, sodass wir nicht mehr weitermachen werden. Der endgültige Block ist wichtig, um sicherzustellen, dass die Bereinigung erfolgt.
Die Idee einer Ausnahme, die die Ausführung immer stoppt, kann für jemanden schwer zu verstehen sein, bis er eine gewisse Erfahrung hat, aber das ist in der Tat die Art und Weise, Dinge immer zu tun. Wenn ein Fehler aufgetreten ist, war er entweder so geringfügig, dass Sie ihn zunächst hätten berücksichtigen müssen, oder es warten immer mehr Fehler auf Sie.
Fehler "schlucken" - sie zu fangen und weiterzumachen ist das Schlimmste, was Sie tun können, weil Ihr Programm unvorhersehbar wird und Sie keine Fehler finden und beheben können.
Gut geschriebener Code enthält so viele try ... finally-Blöcke wie nötig, um sicherzustellen, dass Ressourcen unabhängig vom Ergebnis immer freigegeben werden. Gut geschriebener Code enthält jedoch im Allgemeinen nur eine geringe Anzahl von try ... catch-Blöcken, die in erster Linie vorhanden sind, damit eine Anwendung so ordnungsgemäß wie möglich fehlschlägt oder an den Benutzer zurückgestellt wird, was bedeutet, dass zumindest immer eine Nachricht an den Benutzer usw. weitergeleitet wird. Aber normalerweise fängt man nicht nur einen Fehler und macht weiter.
quelle
Ich weiß, dass dies eine sehr alte Frage ist, aber ich bin heute auf sie gestoßen und war durch die gegebenen Antworten verwirrt. Ich meine, sie sind alle richtig, aber alle antworten auf theoretischer oder sogar philosophischer Ebene, wenn es eine sehr einfache praktische Antwort auf diese Frage gibt.
Wenn Sie ein return-, break-, continue- oder ein anderes Java-Schlüsselwort eingeben, das die sequentielle Ausführung von Code im catch-Block ändert (oder sogar den try-Block) , werden die Anweisungen im finally-Block weiterhin ausgeführt.
Zum Beispiel:
public void myFunc() { double p = 1.0D; String str = "bla"; try{ p = Double.valueOf(str); } catch(Exception ex){ System.out.println("Exception Happened"); return; //return statement here!!! }finally{ System.out.println("Finally"); } System.out.println("After finally"); }
Bei Ausführung wird dieser Code gedruckt:
Das ist der wichtigste Grund für die Existenz eines endgültigen Blocks. Die meisten Antworten implizieren es oder beziehen sich auf es am Rande, aber keine von ihnen betont es. Ich denke, weil dies eine Art Neuling-Frage ist, ist eine so einfache Antwort sehr wichtig.
quelle
Das Highlight ist, dass ein
finally
Block garantiert ausgeführt wird, auch wenn eine Ausnahme ausgelöst und nicht abgefangen wird . Anschließend verwenden Sie denfinally
Block als einmalige Chance, um die erforderlichen Bereinigungen wie das Schließen von Streams durchzuführen. Der Code nach dem finally-Block wird möglicherweise nie erreicht.Aus dem Java- Tutorial
quelle
Wenn ich die Frage verstehe, fragen Sie, was der Unterschied ist zwischen:
try { Foo f = new Foo(); f.bar(); } finally { Foo.baz(); }
Und:
// This doesn't actually compile because a try block needs a catch and/or finally block try { Foo f = new Foo(); f.bar(); } Foo.baz();
Oder eher:
Foo f = new Foo(); f.bar(); Foo.baz();
Der Unterschied besteht darin, dass der Block im ersten Fall ausgeführt wird, wenn eine
new Foo()
oderf.bar()
eine Ausnahmefinally
ausgelöst wird,Foo.baz()
in den letzten beiden Fällen jedoch nicht: Stattdessen wird die Steuerung übersprungen,Foo.baz()
während die JVM nach einem Ausnahmebehandler sucht.BEARBEITEN
Wenn Sie auf Ihren Kommentar antworten, was ist mit:
Foo f = new Foo(); try { f.bar(); } catch (Exception ex) { // ... } f.baz();
Sie haben Recht, wenn der
catch
Block die Ausnahme nicht erneut auslöst oder von der Methode zurückkehrt, die angibt, dass ein Fehler aufgetreten ist, und dannf.baz()
aufgerufen wird, unabhängig davon, ob eine Ausnahme aufgetreten ist . Selbst in diesem Fallfinally
dient der Block jedoch als Dokumentation,f.baz()
die zur Bereinigung verwendet wird.Noch wichtiger ist, dass die Tatsache, dass eine Ausnahme ausgelöst wurde, normalerweise wichtig ist. Daher ist es sehr schwierig, Code zu schreiben, der weiterhin das tut, was er getan hat, ohne zu wissen, dass eine Ausnahme ausgelöst wurde. Es gibt Zeiten, in denen Ausnahmen auf dumme Dinge hinweisen, die Sie ignorieren können, und in diesem Fall sollten Sie die Ausnahme schlucken. In den meisten Fällen möchten Sie jedoch einen Fehler signalisieren, indem Sie die Ausnahme erneut auslösen (oder eine andere Ausnahme auslösen) oder mit einem Fehlercode von der Methode zurückkehren.
Wenn beispielsweise
f.bar()
aString
in a konvertiert werden sollDouble
und bei einem Fehler a ausgelöst wirdNumberFormatException
, muss der Code nach demtry
Block wahrscheinlich wissen, dass derString
nicht tatsächlich in a konvertiert wurdeDouble
. Im Allgemeinen möchten Sie nach demcatch
Blockieren nicht fortfahren . Stattdessen möchten Sie einen Fehler signalisieren. Dies wird als "Abbruch bei Fehler" bezeichnet (im Vergleich zu "Wiederaufnahme bei Fehler", was wahrscheinlich als "Durcheinander nach einem Fehler mit gekreuzten Fingern" bezeichnet werden sollte).Außer in besonderen Fällen können Sie sich verwirren. Zum Beispiel kann der
catch
könnte Block gesetzt die relevantDouble
zu ,Double.NaN
die speziell zu propagieren Fehler richtig in mathematischen Ausdrücken ausgelegt ist. Selbst in diesem Fallfinally
dient der Block als Dokumentation,f.baz()
die an einer Art Bereinigung beteiligt ist.quelle
Der finally-Block enthält Codezeilen, die ausgeführt werden sollen, unabhängig davon, ob eine Ausnahme abgefangen wurde oder nicht. Auch wenn Sie sich entscheiden, die Ausführung von Code in dieser Methode zu beenden. Code nach dem tcf wird möglicherweise nicht ausgeführt, aber der endgültige Code ist "garantiert" (garantiert im Sinne eines nicht abstürzenden, sofort brechenden, nicht handhabbaren Fehlers).
quelle
Ja, da wäre etwas sehr kritisches falsch.
Und das heißt, Ihr Code würde nur ausgeführt, wenn ein Fehler vorliegt .
Anweisungen im Inneren werden
finally
immer ausgeführt, unabhängig davon, ob eine Ausnahme ausgelöst wird. Das ist der Punkt.quelle
Schließlich Block speziell zum Zeitpunkt der Ausnahmeverhütung verwendet. Wenn ein Laufzeitfehler auftritt, kann das Programm zum Beenden führen. Zu diesem Zeitpunkt wird also finally block aufgerufen, bevor das Programm beendet wird. Normalerweise enthält 'finally' Anweisungen zum Schließen von Verbindungen, Speichern von Vorgängen und Eingaben von Dateien sowie Ausgeben von Vorgängen zum Schließen von Verbindungen.
quelle
Wenn Ihr Code niemals eine Ausnahme auslöst oder Sie alle Ausnahmen verbrauchen, ist dies korrekt. Das passiert nicht immer.
quelle