Wird ein finally-Block immer in Java ausgeführt?


2382

Kann ich angesichts dieses Codes absolut sicher sein, dass der finallyBlock immer ausgeführt wird, egal was something()ist?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}

473
Wenn dies nicht der Fall ist, sollte probablystattdessen das Schlüsselwort benannt werden.
Mittagsseide




27
@ BinoyBabu, Finalizer ! = finally; finalizer == die finalize()Methode.
jaco0646

Antworten:


2698

Ja, finallywird nach der Ausführung der tryoder catchCodeblöcke aufgerufen .

Die einzigen Zeiten, finallydie nicht aufgerufen werden, sind:

  1. Wenn Sie aufrufen System.exit()
  2. Wenn Sie aufrufen Runtime.getRuntime().halt(exitStatus)
  3. Wenn die JVM zuerst abstürzt
  4. Wenn die JVM eine Endlosschleife (oder eine andere nicht unterbrechbare, nicht terminierende Anweisung) im Block tryoder erreichtcatch
  5. Wenn das Betriebssystem den JVM-Prozess zwangsweise beendet; zB kill -9 <pid>unter UNIX
  6. Wenn das Hostsystem stirbt; zB Stromausfall, Hardwarefehler, Betriebssystempanik usw.
  7. Wenn der finallyBlock von einem Daemon-Thread ausgeführt werden soll und alle anderen Nicht-Daemon-Threads, die zuvor beendet wurden, finallyaufgerufen werden

44
thread.stop()Verhindert eigentlich nicht unbedingt die finallyAusführung des Blocks.
Piotr Findeisen

181
Wie wäre es, wenn wir sagen, dass der finallyBlock nach dem tryBlock aufgerufen wird und bevor die Steuerung auf die folgenden Anweisungen übergeht. Dies steht im Einklang mit dem try-Block, der eine Endlosschleife enthält, und daher wird der finally-Block nie tatsächlich aufgerufen.
Andrzej Doyle

9
Es gibt auch einen anderen Fall, in dem wir verschachtelte Try-Catch-finally- Blöcke verwenden
ruhungry

7
Außerdem wird schließlich der Block nicht aufgerufen, wenn eine Ausnahme vom Daemon-Thread ausgelöst wird.
Amrish Pandey

14
@ BinoyBabu - Das ist über Finalizer, nicht endgültig blockieren
Avmohan

567

Beispielcode:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("finally trumps return.");
    }
}

Ausgabe:

finally trumps return. 
0

18
Zu finallyIhrer Information : In C # ist das Verhalten identisch, abgesehen davon, dass das Ersetzen der Anweisung in der -klausel durch return 2;nicht zulässig ist (Compiler-Fehler).
Alexander Pacha

15
Hier ist ein wichtiges Detail zu beachten: stackoverflow.com/a/20363941/2684342
WoodenKitty

18
Sie können sogar eine finally-Anweisung in den finally-Block selbst einfügen, die dann den vorherigen Rückgabewert überschreibt. Dadurch werden auch unbehandelte Ausnahmen auf magische Weise verworfen. An diesem Punkt sollten Sie erwägen, Ihren Code umzugestalten.
Zyl

8
Das beweist nicht wirklich, dass endlich Trümpfe zurückkehren. Der Rückgabewert wird aus dem Anrufercode gedruckt. Scheint nicht viel zu beweisen.
Trimtab

20
Entschuldigung, aber dies ist eine Demonstration, kein Beweis. Es ist nur ein Beweis, wenn Sie zeigen können, dass sich dieses Beispiel auf allen Java-Plattformen immer so verhält UND dass sich ähnliche Beispiele auch immer so verhalten.
Stephen C

391

Auch wenn es eine schlechte Praxis ist, übertrifft eine return-Anweisung innerhalb des finally-Blocks jede andere return-Anweisung aus dem regulären Block. Das heißt, der folgende Block würde false zurückgeben:

try { return true; } finally { return false; }

Gleiches gilt für das Auslösen von Ausnahmen aus dem finally-Block.


95
Dies ist eine wirklich schlechte Praxis. Weitere Informationen darüber, warum es schlecht ist, finden Sie unter stackoverflow.com/questions/48088/… .
John Meagher

23
Einverstanden. Eine Rückgabe innerhalb von finally {} ignoriert alle in try {} ausgelösten Ausnahmen. Unheimlich!
Neu242

8
@ dominicbri7 Warum denkst du, ist es eine bessere Praxis? Und warum sollte es anders sein, wenn die Funktion / Methode ungültig ist?
CorsiKa

8
Aus dem gleichen Grund verwende ich NIEMALS gotos in meinen C ++ - Codes. Ich denke, dass mehrere Rückgaben das Lesen erschweren und das Debuggen erschweren (in wirklich einfachen Fällen gilt dies natürlich nicht). Ich denke, das ist nur eine persönliche Präferenz, und am Ende können Sie mit beiden Methoden
dasselbe

16
Ich neige dazu, eine Reihe von Rückgaben zu verwenden, wenn ein Ausnahmefall eintritt. Zum Beispiel, wenn (es gibt einen Grund, nicht fortzufahren) zurückkehren;
iHearGeoff

257

Hier sind die offiziellen Wörter aus der Java-Sprachspezifikation.

14.20.2. Ausführung von try-finally und try-catch-finally

Eine tryAnweisung mit einem finallyBlock wird ausgeführt, indem zuerst der tryBlock ausgeführt wird. Dann gibt es eine Wahl:

  • Wenn die Ausführung des tryBlocks normal abgeschlossen ist, [...]
  • Wenn die Ausführung des tryBlocks aufgrund throweines Wertes V abrupt abgeschlossen wird , [...]
  • Wenn die Ausführung des tryBlocks aus einem anderen Grund R abrupt abgeschlossen ist , wird der finallyBlock ausgeführt. Dann gibt es eine Wahl:
    • Wenn der finally-Block normal abgeschlossen wird, wird die tryAnweisung aus Grund R abrupt abgeschlossen .
    • Wenn der finallyBlock aus Grund S abrupt abgeschlossen wird , wird die tryAnweisung aus Grund S abrupt abgeschlossen ( und Grund R wird verworfen ).

Die Spezifikation für returnmacht dies tatsächlich explizit:

JLS 14.17 Die Rückgabeerklärung

ReturnStatement:
     return Expression(opt) ;

Eine returnAnweisung ohne Expression Versuche , die Kontrolle an den Aufrufer der Methode oder des Konstruktors zu übertragen, die sie enthält.

Eine returnAnweisung mit dem Expression Versuch , die Kontrolle an den Aufrufer der Methode zu übertragen, die sie enthält. Der Wert von Expressionwird zum Wert des Methodenaufrufs.

In den vorhergehenden Beschreibungen heißt es " Versuche , die Kontrolle zu übertragen " und nicht nur " Übertragung der Kontrolle ", denn wenn es tryAnweisungen innerhalb der Methode oder des Konstruktors gibt, deren tryBlöcke die returnAnweisung enthalten , werden alle finallyKlauseln dieser tryAnweisungen in der Reihenfolge von innen nach außen ausgeführt , bevor die Kontrolle an den Aufrufer der Methode oder des Konstruktors übertragen wird. Das plötzliche Ausfüllen einer finallyKlausel kann die durch eine returnAnweisung eingeleitete Kontrollübertragung stören .


163

Zusätzlich zu den anderen Antworten ist es wichtig darauf hinzuweisen, dass 'finally' das Recht hat, jede Ausnahme / jeden zurückgegebenen Wert durch den try..catch-Block zu überschreiben. Der folgende Code gibt beispielsweise 12 zurück:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

In ähnlicher Weise löst die folgende Methode keine Ausnahme aus:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

Während die folgende Methode es wirft:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}

63
Es sollte beachtet werden, dass der mittlere Fall genau der Grund ist, warum es absolut schrecklich ist, eine return-Anweisung in einem finally-Block zu haben (sie könnte jedes Throwable verbergen).
Dimitris Andreou

2
Wer will nicht einen Unterdrückten OutOfMemoryError? ;)
RecursiveExceptionException

Ich habe es getestet und es unterdrückt einen solchen Fehler (yipes!). Es generiert auch eine Warnung, wenn ich es kompiliere (yay!). Sie können dies umgehen, indem Sie eine Rückgabevariable definieren und dann return retVal nach dem finallyBlock verwenden, obwohl dies natürlich davon ausgeht, dass Sie einige andere Ausnahmen unterdrückt haben, da der Code sonst keinen Sinn ergeben würde.
Maarten Bodewes

120

Ich habe das obige Beispiel mit geringfügigen Änderungen ausprobiert.

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

Der obige Code gibt aus:

Endlich kehren Trümpfe zurück.
2

Dies liegt daran, dass bei return i;Ausführung iein Wert 2 vorliegt. Danach wird der finallyBlock ausgeführt, dem 12 zugewiesen ist, iund dann System.outwird ausgeführt.

Nach dem Ausführen des finallyBlocks gibt der tryBlock 2 zurück, anstatt 12 zurückzugeben, da diese return-Anweisung nicht erneut ausgeführt wird.

Wenn Sie diesen Code in Eclipse debuggen, haben Sie das Gefühl, dass nach der Ausführung System.outvon finallyblock die returnAnweisung von tryblock erneut ausgeführt wird. Dies ist jedoch nicht der Fall. Es wird einfach der Wert 2 zurückgegeben.


10
Dieses Beispiel ist fantastisch, es fügt etwas hinzu, das in Dutzenden endgültig verwandten Threads nicht erwähnt wurde. Ich denke, kaum ein Entwickler wird das wissen.
Hoffentlich

4
Was wäre, wenn ies kein primitives, sondern ein ganzzahliges Objekt wäre?
Yamcha

Es fällt mir schwer, diesen Fall zu verstehen. In docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.17 heißt es: "Eine return-Anweisung mit einem Ausdruck versucht, die Kontrolle an den Aufrufer der enthaltenen Methode oder des Lambda-Körpers zu übertragen it .... Wenn die Auswertung des Ausdrucks normal abgeschlossen wird und ein Wert V erzeugt wird. "Was ich aus dieser Aussage erraten könnte, ist, dass return den Ausdruck nicht erneut auswertet, sobald er den Wert V auswertet. Deshalb wurde i geändert wirkt sich nicht auf den zurückgegebenen Wert aus, korrigieren Sie mich.
Meexplorer

Aber ich konnte keinen Beweis dafür finden, wo erwähnt wird, dass return den Ausdruck nicht erneut auswertet.
Meexplorer

1
@meexplorer etwas spät, aber es wird in JLS 14.20.2 erklärt. Ausführung von try-finally und try-catch-finally - etwas kompliziert formuliert, 14.17. Die Rückgabeerklärung muss auch gelesen werden
user85421

117

Hier ist eine Ausarbeitung von Kevins Antwort . Es ist wichtig zu wissen, dass der zurückzugebende Ausdruck vorher ausgewertet wird finally, auch wenn er danach zurückgegeben wird.

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int printX() {
    System.out.println("X");
    return 0;
}

public static int test() {
    try {
        return printX();
    }
    finally {
        System.out.println("finally trumps return... sort of");
    }
}

Ausgabe:

X
finally trumps return... sort of
0

8
Wichtig zu wissen.
Aminadav Glickshtein

Gut zu wissen und macht auch Sinn. Es scheint, dass die tatsächliche Rückgabe des Rückgabewerts das ist, worauf es ankommt finally. Die Berechnung des Rückgabewerts ( printX()hier) steht noch bevor.
Albert

ein gutes Beispiel mit allen 3 "zurückkehrenden" Punkten!
Radistao

Nee. Der obige Code sollte ersetzt werden System.out.println("finally trumps return... sort of");durchSystem.out.print("finally trumps return in try"); return 42;
Pacerier

54

Das ist die ganze Idee eines endgültigen Blocks. Auf diese Weise können Sie sicherstellen, dass Sie Aufräumarbeiten durchführen, die andernfalls möglicherweise übersprungen werden, da Sie unter anderem natürlich zurückkehren.

Wird schließlich aufgerufen, unabhängig davon, was im try-Block passiert (es sei denn, Sie rufen an System.exit(int)oder die Java Virtual Machine startet aus einem anderen Grund).


Das ist eine äußerst schwache Antwort. stackoverflow.com/a/65049/715269
Gangnus

42

Eine logische Art, darüber nachzudenken, ist:

  1. Code, der in einem finally-Block platziert wird, muss ausgeführt werden, unabhängig davon, was im try-Block vorkommt
  2. Wenn also der Code im try-Block versucht, einen Wert zurückzugeben oder eine Ausnahme auszulösen, wird das Element 'in das Regal' gestellt, bis der finally-Block ausgeführt werden kann
  3. Da Code im finally-Block (per Definition) eine hohe Priorität hat, kann er zurückgeben oder werfen, was er will. In diesem Fall wird alles, was noch im Regal liegt, weggeworfen.
  4. Die einzige Ausnahme ist, wenn die VM während des try-Blocks vollständig heruntergefahren wird, z. B. durch 'System.exit'.

10
Ist dies nur "eine logische Art, darüber nachzudenken" oder ist es wirklich so, wie der finally-Block gemäß den Spezifikationen funktionieren soll? Ein Link zu einer Sun-Ressource wäre hier sehr interessant.
Matias

21

Schließlich wird immer ausgeführt, es sei denn, es liegt eine abnormale Programmbeendigung vor (wie das Aufrufen von System.exit (0) ..). Ihr Sysout wird also gedruckt



18

Der finally-Block wird immer ausgeführt, es sei denn, es liegt eine abnormale Programmbeendigung vor, die entweder auf einen JVM-Absturz oder auf einen Aufruf von zurückzuführen ist System.exit(0).

Darüber hinaus überschreibt jeder Wert, der aus dem finally-Block zurückgegeben wird, den vor der Ausführung des finally-Blocks zurückgegebenen Wert. Überprüfen Sie daher alle Exit-Punkte, wenn Sie try finally verwenden.


18

Nein, nicht immer ein Ausnahmefall ist // System.exit (0); bevor der finally-Block verhindert, dass finally ausgeführt wird.

  class A {
    public static void main(String args[]){
        DataInputStream cin = new DataInputStream(System.in);
        try{
            int i=Integer.parseInt(cin.readLine());
        }catch(ArithmeticException e){
        }catch(Exception e){
           System.exit(0);//Program terminates before executing finally block
        }finally{
            System.out.println("Won't be executed");
            System.out.println("No error");
        }
    }
}

Und das ist einer der Gründe, warum Sie System.exit () wirklich niemals aufrufen sollten ...
Franz D.

13

Schließlich wird immer ausgeführt, das ist der springende Punkt, nur weil es nach der Rückgabe im Code erscheint, heißt das nicht, dass es so implementiert ist. Die Java-Laufzeit hat die Verantwortung, diesen Code beim Verlassen des tryBlocks auszuführen .

Zum Beispiel, wenn Sie Folgendes haben:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

Die Laufzeit generiert ungefähr Folgendes:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

Wenn eine nicht erfasste Ausnahme ausgelöst wird, wird der finallyBlock ausgeführt und die Ausnahme wird fortgesetzt.


11

Dies liegt daran, dass Sie den Wert von i als 12 zugewiesen haben, aber den Wert von i nicht an die Funktion zurückgegeben haben. Der richtige Code lautet wie folgt:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}

10

Weil ein finally-Block immer aufgerufen wird, es sei denn, Sie rufen auf System.exit()(oder der Thread stürzt ab).


10

In der offiziellen Java-Dokumentation ( hier klicken ) steht kurz gesagt:

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.


10

Die Antwort ist einfach JA .

EINGANG:

try{
    int divideByZeroException = 5 / 0;
} catch (Exception e){
    System.out.println("catch");
    return;    // also tried with break; in switch-case, got same output
} finally {
    System.out.println("finally");
}

AUSGABE:

catch
finally

1
Die Antwort ist einfach NEIN.
Christophe Roussy

1
@ChristopheRoussy Wie? Kannst du bitte erklären?
Treffen Sie den

1
Lesen Sie die akzeptierte Antwort. Die ursprüngliche Frage lautet "Wird sie immer ausgeführt?" und nicht immer. In Ihrem Fall wird dies jedoch die ursprüngliche Frage nicht beantworten und kann sogar Anfänger irreführen.
Christophe Roussy

In welchem ​​Fall wird es dann nicht ausgeführt?
Treffen Sie sich

In allen Fällen, die in anderen Antworten erwähnt werden, siehe akzeptierte Antwort mit mehr als 1000 Upvotes.
Christophe Roussy

9

Ja, es wird angerufen. Das ist der springende Punkt, um endlich ein Schlüsselwort zu haben. Wenn das Herausspringen aus dem try / catch-Block nur den finally-Block überspringen konnte, war dies dasselbe wie das Platzieren von System.out.println außerhalb des try / catch.


9

Ja, schließlich wird der Block immer ausgeführt. Die meisten Entwickler verwenden diesen Block zum Schließen der Datenbankverbindung, des Ergebnismengenobjekts und des Anweisungsobjekts und verwenden ihn auch im Java-Ruhezustand, um die Transaktion zurückzusetzen.


9

NICHT IMMER

Die Java - Language - Spezifikation beschreibt , wie try- catch- finallyund try- catchBlöcke an Arbeit 14.20.2
Nirgends es gibt an, dass der finallyBlock wird immer ausgeführt. In allen Fällen, in denen die Blöcke try- catch- finallyund try- finallyvollständig sind, wird jedoch angegeben, dass vor Abschluss die Blöcke finallyausgeführt werden müssen.

try {
  CODE inside the try block
}
finally {
  FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).

Das JLS garantiert nicht, dass FIN nach CODE ausgeführt wird . Das JLS garantiert, dass bei Ausführung von CODE und NEXT FIN immer nach CODE und vor NEXT ausgeführt wird .

Warum garantiert das JLS nicht, dass der finallyBlock immer nach dem tryBlock ausgeführt wird? Weil es unmöglich ist. Es ist unwahrscheinlich, aber möglich, dass die JVM unmittelbar nach Abschluss des tryBlocks, jedoch vor der Ausführung des finallyBlocks abgebrochen wird (Kill, Crash, Power Off) . Das JLS kann nichts tun, um dies zu vermeiden.

Daher ist jede Software, die für ihr korrektes Verhalten davon abhängt, dass finallyBlöcke immer ausgeführt werden, nachdem ihre tryBlöcke vollständig sind, fehlerhaft.

returnAnweisungen im tryBlock sind für dieses Problem irrelevant. Wenn die Ausführung nach try- catch- den Code erreicht finally, wird garantiert, dass der finallyBlock zuvor mit oder ohne returnAnweisungen innerhalb des tryBlocks ausgeführt wurde.


8

Ja, es wird. Egal, was in Ihrem Try- oder Catch-Block passiert, es sei denn, System.exit () wird aufgerufen oder JVM stürzt ab. Wenn sich in den Blöcken eine return-Anweisung befindet, wird diese schließlich vor dieser return-Anweisung ausgeführt.


8

Ja, es wird. Nur wenn dies nicht der Fall ist, wird JVM beendet oder stürzt ab


8

Das Hinzufügen zu @ vibhashs Antwort als keine andere Antwort erklärt, was im Fall eines veränderlichen Objekts wie dem folgenden passiert.

public static void main(String[] args) {
    System.out.println(test().toString());
}

public static StringBuffer test() {
    StringBuffer s = new StringBuffer();
    try {
        s.append("sb");
        return s;
    } finally {
        s.append("updated ");
    }
}

Wird ausgegeben

sbupdated 

Ab Java 1.8.162 ist dies nicht die Ausgabe.
Sam

8

Ich habe es versucht, es ist Single-Threaded.

public static void main(String args[]) throws Exception {
    Object obj = new Object();
    try {
        synchronized (obj) {
            obj.wait();
            System.out.println("after wait()");
        }
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

Der main Threadwird für immer im waitZustand sein, daher finallywird er niemals genannt werden ,

Die Konsolenausgabe wird also nicht print String: nach wait()oderfinally

In Übereinstimmung mit @Stephen C ist das obige Beispiel einer der dritten Fälle, die hier erwähnt werden :

Hinzufügen weiterer solcher Endlosschleifenmöglichkeiten im folgenden Code:

// import java.util.concurrent.Semaphore;

public static void main(String[] args) {
    try {
        // Thread.sleep(Long.MAX_VALUE);
        // Thread.currentThread().join();
        // new Semaphore(0).acquire();
        // while (true){}
        System.out.println("after sleep join semaphore exit infinite while loop");
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

Fall 2: Wenn die JVM zuerst abstürzt

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public static void main(String args[]) {
    try {
        unsafeMethod();
        //Runtime.getRuntime().halt(123);
        System.out.println("After Jvm Crash!");
    } catch (Exception e) {
    } finally {
        System.out.println("finally");
    }
}

private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    unsafe.putAddress(0, 0);
}

Ref: Wie stürzt man eine JVM ab?

Fall 6: Wenn der finallyBlock vom Daemon ausgeführt werden soll Threadund alle anderen Nicht-Daemon-Exits Threadszuvor finallyaufgerufen werden.

public static void main(String args[]) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                printThreads("Daemon Thread printing");
                // just to ensure this thread will live longer than main thread
                Thread.sleep(10000);
            } catch (Exception e) {
            } finally {
                System.out.println("finally");
            }
        }
    };
    Thread daemonThread = new Thread(runnable);
    daemonThread.setDaemon(Boolean.TRUE);
    daemonThread.setName("My Daemon Thread");
    daemonThread.start();
    printThreads("main Thread Printing");
}

private static synchronized void printThreads(String str) {
    System.out.println(str);
    int threadCount = 0;
    Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
    for (Thread t : threadSet) {
        if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
            System.out.println("Thread :" + t + ":" + "state:" + t.getState());
            ++threadCount;
        }
    }
    System.out.println("Thread count started by Main thread:" + threadCount);
    System.out.println("-------------------------------------------------");
}

Ausgabe: Dies gibt nicht "finally" aus, was bedeutet, dass "finally block" im "Daemon-Thread" nicht ausgeführt wurde

main Thread Printing  
Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED  
Thread :Thread[main,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE   
Thread count started by Main thread:3  
-------------------------------------------------  
Daemon Thread printing  
Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE  
Thread count started by Main thread:2  
-------------------------------------------------  

Process finished with exit code 0

4
Siehe die akzeptierte Antwort. Dies ist nur ein Randfall der "Endlosschleife".
Stephen C

8

Betrachten Sie das folgende Programm:

public class SomeTest {

    private static StringBuilder sb = new StringBuilder();

    public static void main(String args[]) {

        System.out.println(someString());
        System.out.println("---AGAIN---");
        System.out.println(someString());
        System.out.println("---PRINT THE RESULT---");
        System.out.println(sb.toString());
    }

    private static String someString() {

        try {
            sb.append("-abc-");
            return sb.toString();

        } finally {
            sb.append("xyz");
        }
    }
}

Ab Java 1.8.162 gibt der obige Codeblock die folgende Ausgabe aus:

-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz

Dies bedeutet, dass das Freigeben finallyvon Objekten eine gute Vorgehensweise wie der folgende Code ist:

private static String someString() {

    StringBuilder sb = new StringBuilder();

    try {
        sb.append("abc");
        return sb.toString();

    } finally {
        sb = null; // Just an example, but you can close streams or DB connections this way.
    }
}

Sollte es nicht sb.setLength(0)endlich sein?
user7294900

sb.setLength (0) leert nur die Daten im StringBuffer. Sb = null trennt das Objekt also von der Referenz.
Sam

Sollte "xyz" nicht zweimal in der Ausgabe gedruckt werden? Da die Funktion zweimal aufgerufen wurde, warum war "endlich" nur einmal?
Fresko

2
Dies ist keine gute Praxis. Dieser endgültige Block sb = null;fügt nur nicht benötigten Code hinzu. Ich verstehe, dass Sie meinen, dass ein finallyBlock ein guter Ort ist, um Ressourcen wie eine Datenbankverbindung oder ähnliches freizugeben, aber denken Sie daran, dass Ihr Beispiel Neulinge verwirren könnte.
Roc Boronat

1
@ Samim Danke, ich habe die Zeilen hinzugefügt System.out.println("---AGAIN2---"); System.out.println(sb);und es ist jetzt klarer. So wie es war, war die Ausgabe gegen Ihre These: p Ich habe auch zu Ihrer Antwort hinzugefügt, aber die Bearbeitung muss von einem Moderator oder einer ähnlichen Person akzeptiert werden.
Sonst

7

Das ist tatsächlich in jeder Sprache der Fall ... wird schließlich immer vor einer return-Anweisung ausgeführt, unabhängig davon, wo sich diese return im Methodenkörper befindet. Wenn das nicht der Fall wäre, hätte der finally-Block nicht viel Bedeutung.


7

Zusätzlich zu dem Punkt über die Rückgabe beim endgültigen Ersetzen einer Rückgabe im try-Block gilt das Gleiche für eine Ausnahme. Ein finally-Block, der eine Ausnahme auslöst, ersetzt eine Rückgabe oder Ausnahme, die aus dem try-Block ausgelöst wird.


7

finally wird ausgeführt und das ist sicher.

finally wird in den folgenden Fällen nicht ausgeführt:

Fall 1 :

Wenn Sie ausführen System.exit().

Fall 2:

Wenn Ihre JVM / Thread abstürzt.

Fall 3:

Wenn Ihre Ausführung zwischendurch manuell gestoppt wird.


6
  1. Schließlich wird Block immer ausgeführt. Es sei denn und bis dort die Anweisung System.exit () vorhanden ist (erste Anweisung im Block finally).
  2. Wenn system.exit () die erste Anweisung ist, wird der finally-Block nicht ausgeführt und die Steuerung kommt aus dem finally-Block heraus. Immer wenn die System.exit () -Anweisung in den finally-Block gelangt, bis dieser Anweisung finally-Block ausgeführt wird, und wenn System.exit () angezeigt wird, kommt die Steuerkraft vollständig aus dem finally-Block heraus.

1
Dies wurde schon oft beantwortet. Welche neuen Informationen fügt Ihre Antwort hinzu?
Tom
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.