Läuft ein finally-Block, selbst wenn Sie eine neue Ausnahme auslösen?

142

In diesem Code wird someVargesetzt, auch wenn der catch-Block ausgeführt wird und die zweite Ausnahme ausgelöst wird?

public void someFunction() throws Exception {
    try {
        //CODE HERE
    } catch (Exception e) {
        Log.e(TAG, "", e);
        throw new Exception(e);
    } finally {
        this.someVar= true;
    }
}
jax
quelle
2
Weil es Umstände gibt, in denen das Verhalten nicht wie erwartet ist, wie von @GaryF
jax
1
Es ist anzumerken, dass der letzte Block möglicherweise nicht wie erwartet ausgeführt wird, wenn er eine Ausnahme auslöst oder eine Rückgabe ausführt.
Peter Lawrey

Antworten:

184

Ja, die finally-Blöcke werden immer ausgeführt ... außer wenn:

  • Der Thread, der den try-catch-finally-Block ausführt, wird beendet oder unterbrochen
  • Sie nutzen System.exit(0);
  • Die zugrunde liegende VM wird auf andere Weise zerstört
  • Die zugrunde liegende Hardware ist in irgendeiner Weise unbrauchbar

Wenn eine Methode in Ihrem finally-Block eine nicht erfasste Ausnahme auslöst, wird danach nichts mehr ausgeführt (dh die Ausnahme wird wie in jedem anderen Code ausgelöst). Ein sehr häufiger Fall, in dem dies geschieht, ist java.sql.Connection.close().

Abgesehen davon vermute ich, dass das von Ihnen verwendete Codebeispiel nur ein Beispiel ist, aber achten Sie darauf, dass die tatsächliche Logik nicht in einen finally-Block eingefügt wird. Der finally-Block ist für die Bereinigung von Ressourcen (Schließen von DB-Verbindungen, Freigeben von Dateihandles usw.) vorgesehen, nicht für die Logik, die ausgeführt werden muss. Wenn es ausgeführt werden muss, tun Sie es vor dem Try-Catch-Block, weg von etwas, das eine Ausnahme auslösen könnte, da Ihre Absicht mit ziemlicher Sicherheit funktional dieselbe ist.

GaryF
quelle
4
Was meinst du hier mit "Der Thread, der den try-catch-finally-Block ausführt, ist [...] unterbrochen"? Möglicherweise ist diese Dokumentation schlecht formuliert, aber Thread.interrupt () führt nicht dazu, dass der finally-Block übersprungen wird, unabhängig davon, ob er aus dem try- oder dem catch-Block geworfen wird. Bedeutet dies "unterbrochen", um etwas Gewalttätigeres wie Thread.stop () zu bedeuten?
Joe Kearney
@ Joe: Ja, ich denke, die Dokumentation ist hier etwas schlecht formuliert und bedeutet eine allgemeine Unterbrechung der Aktivität des Threads.
GaryF
@ GaryF - Ich denke, Sie zitieren aus dem JLS. Der Wortlaut des JLS ist manchmal etwas seltsam, aber Sie werden normalerweise feststellen, dass die Bedeutung der seltsamen Terminologie an anderer Stelle im Dokument klar definiert ist. Das JLS ist eine Spezifikation und hat als Hauptziel Präzision (und nicht Lesbarkeit).
Stephen C
1
@Stephen C - Eigentlich kam das aus dem JavaSE-Tutorial (von anderen verlinkt). Es mag im JLS ähnlich formuliert sein, aber ich kann den relevanten Teil nicht finden. Ich hätte dies in Kapitel 11 (Ausnahmen), Kapitel 14 (Anweisungen) oder Kapitel 15 (Ausdrücke) erwartet, kann aber nichts sehen, was sich explizit auf Unterbrechungen bezieht. Das würde mich sicherlich interessieren.
GaryF
1
@ GaryF - Ich verstehe. Tatsächlich spricht das JLS von einer "normalen" und "abrupten" Beendigung von Anweisungen, und es gibt einen Abschnitt (14.1), der die Terminologie definiert. Das Verhalten von finallywird dann in Form von normalen und abrupten Abbrüchen angegeben.
Stephen C
10

Ja.

Siehe die Dokumentation :

Der finally-Block wird immer ausgeführt, wenn der try-Block beendet wird.

Ausnahmen:

Hinweis: Wenn die JVM beendet wird, während der Try- oder Catch-Code ausgeführt wird, wird der finally-Block möglicherweise nicht ausgeführt. Wenn der Thread, der den Try- oder Catch-Code ausführt, unterbrochen oder beendet wird, wird der finally-Block möglicherweise nicht ausgeführt, obwohl die gesamte Anwendung fortgesetzt wird.

froadie
quelle
2

Schließlich wird der Block immer ausgeführt.

public class ExceptionTest {

public static void someFunction(String input) throws Exception {
    try {
        if( input.equals("ABC") ) {
            System.out.println("Matched");
        }
    } catch (Exception e) {
        throw new Exception(e);
    } finally {
        System.out.println("Input Is "+input+" Finally Executed!!!");
    }
}

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    try {
        System.out.println("********* Test with VALUE ********* ");
        someFunction("ABC");
        System.out.println("\r\n********* Test with NULL  ********* ");
        someFunction(null);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}}

Java Try Catch Endlich Block mit Throw

Vasanth Umapathy
quelle
2

Schließlich wird immer ausgeführt, egal was Ihr Fall ist, dh

  • try-catch-finally-Block
  • wirft

Für ungeprüfte Ausnahmen schreibt Java keine Fehlerbehandlung vor. Aus diesem Grund wird der unter diesem Punkt (an dem der Fehler aufgetreten ist) geschriebene Code nicht ausgeführt, wenn im finally-Block eine ungeprüfte Ausnahme auftritt und dann keine Behandlung durchgeführt wird.

Daher schlage ich vor, immer alle Ausnahmen zu behandeln, wenn diese aktiviert oder deaktiviert sind. Auf diese Weise können Sie sicherstellen, dass der Codeblock in finally auch ausgeführt wird, unabhängig davon, ob auch eine nicht aktivierte Ausnahme auftritt. Sie haben einen Platz in Fangunter Nest und schließlich blockieren Ihre notwendige Arbeit zu erledigen.

yug
quelle
1

Ja. finallyBlock wird immer ausgeführt, außer in dem Fall, in dem Sie System.exit () aufrufen, da Java VM gestoppt wird.

Vladimir Ivanov
quelle
Shutdown-Hooks werden weiterhin nach System.exit () aufgerufen, aber vorhandene Nicht-System-Threads werden alle gestoppt.
Peter Lawrey