java - übersicht - try catch finally return c#




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

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

Kann ich angesichts dieses Codes absolut sicher sein, dass der finally Block 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.");
}


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

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());
    }

    private static String someString() {

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

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

Ab Java 1.8.162 liefert der obige Codeblock die folgende Ausgabe:

-abc-
---AGAIN---
-abc-xyz-abc-

Dies bedeutet, dass die finally Freigabe von Objekten eine bewährte Methode ist, wie im folgenden Code:

private static String someString() {

    StringBuilder sb = new StringBuilder();

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

    } finally {
        sb = null;
    }
}

Das ist die ganze Idee eines endgültigen Blocks. So können Sie sicherstellen, dass Sie Aufräumarbeiten durchführen, die ansonsten übersprungen werden könnten, da Sie unter anderem natürlich zurückkehren.

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


Das ist eigentlich in jeder Sprache wahr ... wird letztlich 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 endgültige Block keine große Bedeutung.


Der finally-Block wird immer ausgeführt, es sei denn, es liegt eine ungewöhnliche Programmbeendigung vor, die entweder auf einen Absturz der JVM oder auf einen Aufruf von System.exit(0) .

Darüber hinaus überschreibt jeder Wert, der aus dem finally-Block zurückgegeben wird, den Wert, der vor der Ausführung des finally-Blocks zurückgegeben wird. Daher sollten Sie bei der Verwendung von try finally alle Exit-Punkte überprüfen.


Ein logischer Weg, um darüber nachzudenken, ist:

  1. Code, der in einem finally-Block platziert wird, muss ausgeführt werden, was auch immer im try-Block geschieht
  2. Wenn also 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 der Code im finally-Block (per Definition) eine hohe Priorität hat, kann er zurückgeben oder werfen, was immer er möchte. In diesem Fall wird alles, was sich noch im Regal befindet, verworfen.
  4. Die einzige Ausnahme ist, wenn die VM während des try-Blocks vollständig heruntergefahren wird, z. B. durch 'System.exit'.

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

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

Eine try Anweisung mit einem finally Block wird ausgeführt, indem zuerst der try Block ausgeführt wird. Dann gibt es eine Wahl:

  • Wenn die Ausführung des try Blocks normal abgeschlossen ist, [...]
  • Wenn die Ausführung des try Blocks abrupt durch einen Wert von V beendet wird , [...]
  • Wenn die Ausführung des try Blocks aus irgendeinem anderen Grund R abrupt abgeschlossen ist, wird der finally Block ausgeführt. Dann gibt es eine Wahl:
    • Wenn der finally-Block normal abgeschlossen wird, wird die try Anweisung aus Gründen R abrupt beendet.
    • Wenn der finally Block aus Gründen S abrupt abgeschlossen wird, wird die try Anweisung aus Gründen S abrupt beendet ( und der Grund R wird verworfen ).

Die return macht dies tatsächlich deutlich:

JLS 14.17 Die Erklärung zur Rückkehr

ReturnStatement:
     return Expression(opt) ;

Eine return Anweisung ohne Expression versucht , die Kontrolle an den Aufrufer der Methode oder des Konstruktors zu übergeben, der sie enthält.

Eine return Anweisung mit einem Expression versucht , die Kontrolle der aufrufenden Methode an den Aufrufer zu übergeben. Der Wert des Expression wird zum Wert des Methodenaufrufs.

Die vorangegangenen Beschreibungen sagen " Versuche zum Übertragen der Kontrolle " und nicht nur " Übertragen der Kontrolle ". Wenn in der Methode oder im Konstruktor try Anweisungen vorhanden sind, deren try Blöcke die return Anweisung enthalten, werden alle finally Klauseln dieser try Anweisungen ausgeführt Reihenfolge, bis zum weitesten Ende, bevor die Kontrolle an den Aufrufer der Methode oder des Konstruktors übergeben wird. Das abrupte Abschließen einer finally Klausel kann die durch eine return Anweisung initiierte Übertragung der Kontrolle stören.


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.");
    }
}

Die obigen Code-Ausgaben:

endlich trumpft zurück.
2

Dies ist so, wenn return i; ausgeführt wird, hat i einen Wert 2. Danach wird der finally Block ausgeführt, wobei 12 i zugewiesen wird und dann System.out out ausgeführt wird.

Nach der Ausführung des finally Blocks gibt der try Block 2 zurück statt 12, da diese return-Anweisung nicht erneut ausgeführt wird.

Wenn Sie diesen Code in Eclipse debuggen, haben Sie das Gefühl, dass nach Ausführung des System.out Befehls System.out die return Anweisung des try Blocks erneut ausgeführt wird. Dies ist jedoch nicht der Fall. Es gibt einfach den Wert 2 zurück.


Ja, es wird gerufen. Das ist der springende Punkt, wenn man ein finales Keyword hat. Wenn aus dem try / catch-Block herausspringen konnte, konnte der endgültige Block einfach übersprungen werden. Dies war das gleiche, als würde man die System.out.println außerhalb des try / catch-Blocks platzieren.


Ja, es wird. Egal, was in Ihrem try- oder catch-Block passiert, sofern nicht System.exit () aufgerufen oder die JVM abgestürzt ist. Wenn in den Blöcken eine return-Anweisung enthalten ist, wird sie vor dieser return-Anweisung ausgeführt.


Ja, wird nach der Ausführung der try- oder catch-Codeblöcke finally aufgerufen.

Die einzigen Zeiten werden finally nicht aufgerufen werden:

  1. Wenn Sie System.exit() aufrufen;
  2. Wenn die JVM zuerst abstürzt;
  3. Wenn die JVM eine Endlosschleife (oder eine andere nicht unterbrechbare, nicht beendende Anweisung) im try oder catch Block erreicht.
  4. Wenn das Betriebssystem den JVM-Prozess zwangsweise beendet; zB "kill -9" unter UNIX.
  5. Wenn das Hostsystem stirbt; zB Stromausfall, Hardwarefehler, Betriebssystempanik usw.
  6. Wenn finally-Block vom Daemon-Thread ausgeführt wird, werden alle anderen Nicht-Daemon-Threads beendet, bevor final aufgerufen wird.

Kurz gesagt, in der offiziellen Java-Dokumentation ( here klicken) steht Folgendes geschrieben:

Wenn die JVM beendet wird, während der try- oder catch-Code ausgeführt wird, wird der finally-Block möglicherweise nicht ausgeführt. Ebenso kann der finally-Block möglicherweise nicht ausgeführt werden, wenn der Thread, der den try- oder catch-Code ausführt, unterbrochen oder beendet wird, obwohl die Anwendung insgesamt fortgesetzt wird.


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

  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");
        }
    }
}

Probieren Sie diesen Code aus. Sie werden verstehen, dass der Code im nach dem return-Befehl ausgeführten Block ausgeführt wird .

public class TestTryCatchFinally {
    static int x = 0;

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

    public static int f1(){
        try{
            x = 1;
            return x;
        }finally{
            x = 2;
        }
    }

    public static int f2(){
        return x;
    }
}

Schließlich wird immer ausgeführt, dass dies der springende Punkt ist, nur weil es nach der Rückkehr im Code angezeigt wird, bedeutet dies nicht, dass es so implementiert wird. Die Java-Laufzeitumgebung ist dafür verantwortlich, diesen Code auszuführen, wenn der try Block beendet wird.

Zum Beispiel, wenn Sie Folgendes haben:

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

Die Laufzeit erzeugt so etwas:

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

Wenn eine nicht erfasste Ausnahme ausgelöst wird, wird der finally Block ausgeführt und die Ausnahme wird weiter verbreitet.


Schliesslich wird es immer ausgeführt, es sei denn, es liegt eine ungewöhnliche Programmbeendigung vor (z. B. Aufruf von System.exit (0) ..). Ihr Sysout wird also gedruckt


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


Wenn eine Ausnahme ausgelöst wird, läuft sie schließlich. Wenn eine Ausnahme nicht ausgelöst wird, wird schließlich ausgeführt. Wenn die Ausnahme abgefangen wird, wird schließlich ausgeführt. Wenn die Ausnahme nicht abgefangen wird, wird schließlich ausgeführt.

Nur wenn es nicht läuft, wird die JVM beendet.





try-catch-finally