Does a finally block always get executed in Java?

前端 未结 30 1580
逝去的感伤
逝去的感伤 2020-11-21 07:24

Considering this code, can I be absolutely sure that the finally block always executes, no matter what something() is?

try         


        
相关标签:
30条回答
  • 2020-11-21 07:47

    finally is always executed unless there is abnormal program termination (like calling System.exit(0)..). so, your sysout will get printed

    0 讨论(0)
  • 2020-11-21 07:48

    Consider the following program:

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

    As of Java 1.8.162, the above code block gives the following output:

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

    this means that using finally to free up objects is a good practice like the following code:

    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.
        }
    }
    
    0 讨论(0)
  • 2020-11-21 07:48

    That's actually true in any language...finally will always execute before a return statement, no matter where that return is in the method body. If that wasn't the case, the finally block wouldn't have much meaning.

    0 讨论(0)
  • 2020-11-21 07:50

    I tried this, It is 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");
        }
    }
    

    The main Thread will be on wait state forever, hence finally will never be called,

    so console output will not print String: after wait() or finally

    Agreed with @Stephen C, the above example is one of the 3rd case mention here:

    Adding some more such infinite loop possibilities in following 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");
        }
    }
    

    Case 2: If the JVM crashes first

    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: How do you crash a JVM?

    Case 6: If finally block is going to be executed by daemon Thread and all other non-daemon Threads exit before finally is called.

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

    output: This does not print "finally" which implies "Finally block" in "daemon thread" did not execute

    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
    
    0 讨论(0)
  • 2020-11-21 07:52

    This is because you assigned the value of i as 12, but did not return the value of i to the function. The correct code is as follows:

    public static int test() {
        int i = 0;
        try {
            return i;
        } finally {
            i = 12;
            System.out.println("finally trumps return.");
            return i;
        }
    }
    
    0 讨论(0)
  • 2020-11-21 07:53

    Adding to @vibhash's answer as no other answer explains what happens in the case of a mutable object like the one below.

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

    Will output

    sbupdated 
    
    0 讨论(0)
提交回复
热议问题