2697 Stimmen

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

Bei diesem Code kann ich 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("Ich weiß nicht, ob das ausgegeben wird");
}

672 Stimmen

Wenn dies nicht der Fall ist, sollte das Schlüsselwort wie folgt lauten probably stattdessen.

61 Stimmen

3 Stimmen

Effektives Java sagt etwas anderes informit.com/articles/article.aspx?p=1216151&seqNum=7

10voto

Wasim Punkte 101

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 setzt return außer Kraft.");
        return i;
    }
}

9voto

Pradeep Kumaresan Punkte 199

Füge hinzu zur Antwort von @vibhash, da keine andere Antwort erklärt, was im Fall eines veränderbaren Objekts wie dem unten stehenden 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("aktualisiert ");
    }
}

Wird ausgeben

sbaktualisiert 

0 Stimmen

Ab Java 1.8.162 ist dies nicht mehr der Fall.

9voto

Karthikeyan Punkte 2418

Ja, das wird es. Egal was in Ihrem try- oder catch-Block passiert, es sei denn, es wird System.exit() aufgerufen oder der JVM crasht. Wenn es eine return-Anweisung in dem/den Block(s) gibt, wird finally vor dieser return-Anweisung ausgeführt.

8voto

sam Punkte 1559

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("---WIEDERHOLEN---");
        System.out.println(someString());
        System.out.println("---ERGEBNIS DRUCKEN---");
        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:

-abc-
---WIEDERHOLEN---
-abc-xyz-abc-
---ERGEBNIS DRUCKEN---
-abc-xyz-abc-xyz

Dies bedeutet, dass es eine gute Praxis ist, finally zum Freigeben von Objekten zu verwenden, wie im folgenden Code:

private static String someString() {

    StringBuilder sb = new StringBuilder();

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

    } finally {
        sb = null; // Nur ein Beispiel, aber Sie können auf diese Weise Streams oder DB-Verbindungen schließen.
    }
}

0 Stimmen

Müsste es nicht heißen sb.setLength(0) in endlich?

0 Stimmen

Sb.setLength(0) leert lediglich die Daten im StringBuffer. Mit sb = null wird also das Objekt von der Referenz getrennt.

0 Stimmen

Sollte "xyz" in der Ausgabe nicht zweimal ausgegeben werden? Da die Funktion zweimal aufgerufen wurde, warum wurde "finally" nur einmal ausgegeben?

8voto

dkb Punkte 3756

Ich habe das ausprobiert, Es ist single-threaded.

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

Der main Thread wird für immer im wait Zustand sein, daher wird finally nie aufgerufen werden,

also wird die Konsolenausgabe nicht den String drucken: nach wait() oder finally

Zustimmung zu @Stephen C, das obige Beispiel ist einer der Fälle, die hier genannt werden:

Füge einige weitere solche Möglichkeiten für endlose Schleifen im folgenden Code hinzu:

// 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("nach sleep join semaphore exit infinite while loop");
    } catch (Exception ignored) {
    } finally {
        System.out.println("endlich");
    }
}

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("Nach dem JVM-Absturz!");
    } catch (Exception e) {
    } finally {
        System.out.println("endlich");
    }
}

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 lässt man eine JVM abstürzen?

Fall 6: Wenn der finally Block von einem Daemon Thread ausgeführt wird und alle anderen nicht-Daemon Threads vor dem Aufruf von finally beendet 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("endlich");
            }
        }
    };
    Thread daemonThread = new Thread(runnable);
    daemonThread.setDaemon(Boolean.TRUE);
    daemonThread.setName("Mein Daemon-Thread");
    daemonThread.start();
    printThreads("main Thread Printing");
}

private static synchronized void printThreads(String str) {
    System.out.println(str);
    int threadCount = 0;
    Set threadSet = Thread.getAllStackTraces().keySet();
    for (Thread t : threadSet) {
        if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
            System.out.println("Thread :" + t + ":" + "Zustand:" + t.getState());
            ++threadCount;
        }
    }
    System.out.println("Thread Count gestartet von Hauptthread:" + threadCount);
    System.out.println("-------------------------------------------------");
}

Output: Dies gibt kein "finally" aus, was darauf hinweist, dass der "Finally-Block" im "Daemon-Thread" nicht ausgeführt wurde

main Thread Printing  
Thread :Thread[Mein Daemon-Thread,5,main]:Zustand:BLOCKED  
Thread :Thread[main,5,main]:Zustand:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:Zustand:RUNNABLE   
Thread Count gestartet von Hauptthread:3  
-------------------------------------------------  
Daemon Thread printing  
Thread :Thread[Mein Daemon-Thread,5,main]:Zustand:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:Zustand:RUNNABLE  
Thread Count gestartet von Hauptthread:2  
-------------------------------------------------  

Prozess beendet mit Exit-Code 0

5 Stimmen

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X