Frage Wird letztendlich immer in Java ausgeführt?


Betrachte diesen Code, kann ich sein absolut sicher dass die finally Block wird immer ausgeführt, egal was passiert 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.");
}

1901
2017-09-15 17:43


Ursprung


Antworten:


Ja, finally wird nach der Ausführung der Versuchs- oder Fangcode-Blöcke aufgerufen.

Die einzigen Zeiten finally werden nicht angerufen werden:

  1. Wenn Sie aufrufen System.exit();
  2. Wenn die JVM zuerst abstürzt;
  3. Wenn die JVM eine Endlosschleife (oder eine andere nicht unterbrechbare, nicht terminierende Anweisung) in der try oder catch Block;
  4. Wenn das Betriebssystem den JVM-Prozess zwangsweise beendet; z.B. "kill -9" unter UNIX.
  5. Wenn das Host-System stirbt; z.B. Stromausfall, Hardwarefehler, OS Panik, und so weiter.
  6. Wenn schließlich der Block vom Daemon-Thread ausgeführt wird und alle anderen Nicht-Daemon-Threads beendet werden, bevor schließlich aufgerufen wird.

2114
2017-09-15 17:45



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

444
2017-09-15 17:59



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

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

Das Gleiche gilt für das Auslösen von Ausnahmen vom finally-Block.


323
2017-09-15 18:19



Hier sind die offiziellen Worte aus der Java Language Specification.

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

EIN try Aussage mit a finally Der Block wird ausgeführt, indem zuerst der Befehl ausgeführt wird try Block. Dann gibt es eine Wahl:

  • Wenn die Ausführung der try Block wird normal abgeschlossen, [...]
  • Wenn die Ausführung der try Der Block wird abrupt wegen a beendet throw eines Wertes V, [...]
  • Wenn die Ausführung der try Block wird aus irgendeinem anderen Grund abrupt beendet R, dann ist die finally Block wird ausgeführt. Dann gibt es eine Wahl:
    • Wenn der finally Block normal beendet wird, dann wird der try Die Anweisung wird abrupt beendet R.
    • Wenn die finally Der Block wird abrupt beendet S, dann ist die try Die Anweisung wird abrupt beendet S (und Grund R wird verworfen).

Die Spezifikation für return macht dies explizit:

JLS 14.17 Die Rückkehrerklärung

ReturnStatement:
     return Expression(opt) ;

EIN return Aussage mit Nein Expression  Versuche Übergeben der Kontrolle an den Aufrufer der Methode oder des Konstruktors, der sie enthält.

EIN return Aussage mit einem Expression  Versuche die Kontrolle auf den Aufrufer der Methode zu übertragen, die sie enthält; der Wert des Expression wird zum Wert des Methodenaufrufs.

Die vorhergehenden Beschreibungen sagen "Versuche um die Kontrolle zu übertragen" anstatt nur "überträgt die Kontrolle"Denn wenn es welche gibt try Anweisungen innerhalb der Methode oder des Konstruktors, deren try Blöcke enthalten die return Aussage, dann irgendwelche finally Klauseln von denen try Anweisungen werden in der Reihenfolge innerlich nach äußerste ausgeführt, bevor die Kontrolle an den Aufrufer der Methode oder des Konstruktors übergeben wird. Abrupte Vollendung eines finally Klausel kann den Kontrollübergang stören, der von a return Erklärung.


229
2018-05-25 06:50



Zusätzlich zu den anderen Antworten ist es wichtig, darauf hinzuweisen, dass "endlich" 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();
    }
}

134
2018-05-13 07:11



Ich habe das obige Beispiel mit leichten Modifikationen versucht-

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 kehrt die Trümpfe zurück.
  2

Dies ist weil return i; wird ausgeführt i hat einen Wert von 2. Danach finally Block wird ausgeführt, wo 12 zugewiesen ist i und dann System.out out wird ausgeführt.

Nach dem Ausführen der finally blockiere die try block gibt 2 zurück, anstatt 12 zurückzugeben, da diese return-Anweisung nicht erneut ausgeführt wird.

Wenn Sie diesen Code in Eclipse debuggen, werden Sie nach der Ausführung ein Gefühl bekommen System.out von finally blockiere die return Aussage von try Block wird erneut ausgeführt. Aber das ist nicht der Fall. Es gibt einfach den Wert 2 zurück.


88
2017-11-17 16:25



Hier ist eine Ausarbeitung von Kevins Antwort. Es ist wichtig zu wissen, dass der auszugebende Ausdruck vorher ausgewertet wird finally, auch wenn es 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

80
2017-12-03 23:36



Das ist die ganze Idee eines Endblocks. Dadurch können Sie natürlich sicherstellen, dass Sie Aufräumarbeiten durchführen, die sonst möglicherweise übersprungen werden, weil Sie unter anderem natürlich zurückkehren.

Endlich wird angerufen egal was passiert im Versuchsblock (es sei denn du rufst an System.exit(int) oder die Java Virtual Machine startet aus einem anderen Grund).


46
2018-05-13 06:19



Ein logischer Weg, darüber nachzudenken, ist:

  1. Code in einem finally Block muss ausgeführt werden was auch immer geschieht innerhalb des Versuchsblocks
  2. Wenn der Code im try-Block versucht, einen Wert zurückzugeben oder eine Ausnahme auszulösen, wird der Artikel "im Regal" platziert, bis der finally-Block ausgeführt werden kann
  3. Da Code im finally-Block (definitionsgemäß) eine hohe Priorität hat, kann er beliebig zurückgeben oder werfen. In diesem Fall wird alles, was auf dem Regal liegt, verworfen.
  4. Die einzige Ausnahme besteht darin, dass die VM während des try-Blocks z. von 'System.exit'

31
2017-09-15 19:26