ChatGPT解决这个技术问题 Extra ChatGPT

Does a finally block always get executed in Java?

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

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}
If it didn't, the keyword should be named probably instead.
@BinoyBabu, finalizer != finally; finalizer == the finalize() method.
@Boann Correct, "not always" indeed. But then you can never ever use the words "guaranteed" or "always".

A
Ali Dehghani

Yes, finally will be called after the execution of the try or catch code blocks.

The only times finally won't be called are:

If you invoke System.exit() If you invoke Runtime.getRuntime().halt(exitStatus) If the JVM crashes first If the JVM reaches an infinite loop (or some other non-interruptable, non-terminating statement) in the try or catch block If the OS forcibly terminates the JVM process; e.g., kill -9 on UNIX If the host system dies; e.g., power failure, hardware error, OS panic, et cetera If the finally block is going to be executed by a daemon thread and all other non-daemon threads exit before finally is called


Actually thread.stop() does not necessarily prevent finally block from being executed.
How about we say that the finally block will be called after the try block, and before control passes to the following statements. That's consistent with the try block involving an infinite loop and hence the finally block never actually being invoked.
there is also another case, when we use nested try-catch-finally blocks
also, finally block is not called in case of exception thrown by daemon thread.
@BinoyBabu - That's about finalizer, not finally block
f
fareed

Example code:

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

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

Output:

something is printed. 
0

FYI: In C# the behaviour is identical apart from the fact that replacing the statement in the finally-clause with return 2; is not allowed (Compiler-Error).
Here is an important detail to be aware of: stackoverflow.com/a/20363941/2684342
You can even add a return statement in the finally block itself, which will then override the previous return value. This also magically discards unhandled exceptions. At that point, you should consider refactoring your code.
That does not really prove that finally trumps return. The return value is printed from the caller code. Doesn't seem to prove much.
Sorry, but this is a demonstration not a proof. It is only a proof if you can show that this example always behaves this way on all Java platforms, AND that similar examples also always behave this way.
M
MooBob42

Also, although it's bad practice, if there is a return statement within the finally block, it will trump any other return from the regular block. That is, the following block would return false:

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

Same thing with throwing exceptions from the finally block.


This is a REALLY bad practice. See stackoverflow.com/questions/48088/… for more info about why it's bad.
Agreed. A return within finally{} ignores any exception thrown in try{}. Scary!
@dominicbri7 Why do you think it's a better practice? And why should it be different when the function/method is void?
For the same reason I NEVER use goto's in my C++ codes. I think multiple returns makes it harder to read and more difficult to debug (of course in really simple cases it doesn't apply). I guess that's just personnal preferrence and in the end you can achieve the same thing using either method
I tend to use a number of returns when some kind of exceptional case happens. Like if(there is a reason not to continue) return;
K
Kenster

Here's the official words from the Java Language Specification.

14.20.2. Execution of try-finally and try-catch-finally

A try statement with a finally block is executed by first executing the try block. Then there is a choice: If execution of the try block completes normally, [...] If execution of the try block completes abruptly because of a throw of a value V, [...] If execution of the try block completes abruptly for any other reason R, then the finally block is executed. Then there is a choice: If the finally block completes normally, then the try statement completes abruptly for reason R. If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).

The specification for return actually makes this explicit:

JLS 14.17 The return Statement

ReturnStatement: return Expression(opt) ; A return statement with no Expression attempts to transfer control to the invoker of the method or constructor that contains it. A return statement with an Expression attempts to transfer control to the invoker of the method that contains it; the value of the Expression becomes the value of the method invocation. The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements within the method or constructor whose try blocks contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.


M
MC Emperor

In addition to the other responses, it is important to point out that 'finally' has the right to override any exception/returned value by the try..catch block. For example, the following code returns 12:

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

Similarly, the following method does not throw an exception:

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

While the following method does throw it:

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

It should be noted that the middle case is precisely the reason why having a return statement inside a finally block is absolutely horrible (it could hide any Throwable).
Who doesn't want a surpressed OutOfMemoryError? ;)
I tested it and it does suppress such an error (yipes!). It also generates a warning when I compile it (yay!). And you can work around it by defining a return variable and then using return retVal after the finally block, although that of course assumes that you suppressed some other exceptions because the code would not make sense otherwise.
J
Jared Rummler

I tried the above example with slight modification-

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

The above code outputs:

finally trumps return. 2

This is because when return i; is executed i has a value 2. After this the finally block is executed where 12 is assigned to i and then System.out out is executed.

After executing the finally block the try block returns 2, rather than returning 12, because this return statement is not executed again.

If you will debug this code in Eclipse then you'll get a feeling that after executing System.out of finally block the return statement of try block is executed again. But this is not the case. It simply returns the value 2.


This example is awesome, it adds something that hasn't been mentioned in dozens finally related threads. I think barely any developer will know this.
What if i was not a primitive, but an Integer object.
I am having a hard time understanding this case. docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.17 says that, "A return statement with an Expression attempts to transfer control to the invoker of the method or lambda body that contains it.... If evaluation of the Expression completes normally, producing a value V.." What I could guess from this statement is- it seems that return doesn't evaluate the expression again once it evaluates value V, that's why changed i doesn't affect the returned value, correct me.
But I coudn't found any proof regarding this, where is it mentioned that return doesn't evaluate the expression again.
@meexplorer a bit late, but it is explained in JLS 14.20.2. Execution of try-finally and try-catch-finally - worded a bit complicated, 14.17. The return Statement must also be read
C
Community

Here's an elaboration of Kevin's answer. It's important to know that the expression to be returned is evaluated before finally, even if it is returned after.

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

Output:

X
finally trumps return... sort of
0

Important to know.
Good to know, and makes sense as well. It seems that actually returning the value of return is what comes after finally. Calculating the return value (printX() here) still comes before it.
Nope. The code above should replace System.out.println("finally trumps return... sort of"); with System.out.print("finally trumps return in try"); return 42;
This answer is completely self-evident IMO because return doesn't return some magic continuation that only gets evaluated if the caller prints it or whatever. printX() gets called before the return happens, regardless of any try/catch, or anything else.
C
Chris Cooper

That is the whole idea of a finally block. It lets you make sure you do cleanups that might otherwise be skipped because you return, among other things, of course.

Finally gets called regardless of what happens in the try block (unless you call System.exit(int) or the Java Virtual Machine kicks out for some other reason).


That is an extremely weak answer. stackoverflow.com/a/65049/715269
G
Garth Gilmour

A logical way to think about this is:

Code placed in a finally block must be executed whatever occurs within the try block So if code in the try block tries to return a value or throw an exception the item is placed 'on the shelf' till the finally block can execute Because code in the finally block has (by definition) a high priority it can return or throw whatever it likes. In which case anything left 'on the shelf' is discarded. The only exception to this is if the VM shuts down completely during the try block e.g. by 'System.exit'


Is this just "a logical way to think about it" or is it really how the finally block is intended to work according to the specifications ? A link to a Sun resource would be very interesting in here.
s
shyam

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


R
Ram

No, not always one exception case is// System.exit(0); before the finally block prevents finally to be executed.

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

And that's one of the reasons you really should never call System.exit()...
J
James A. N. Stauffer

Also a return in finally will throw away any exception. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


Y
Youcef Laidani

The finally block is always executed unless there is abnormal program termination, either resulting from a JVM crash or from a call to System.exit(0).

On top of that, any value returned from within the finally block will override the value returned prior to execution of the finally block, so be careful of checking all exit points when using try finally.


M
Motti

Finally is always run that's the whole point, just because it appears in the code after the return doesn't mean that that's how it's implemented. The Java runtime has the responsibility to run this code when exiting the try block.

For example if you have the following:

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

The runtime will generate something like this:

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

If an uncaught exception is thrown the finally block will run and the exception will continue propagating.


M
Mendelt

Yes it will get called. That's the whole point of having a finally keyword. If jumping out of the try/catch block could just skip the finally block it was the same as putting the System.out.println outside the try/catch.


J
Jay Riggs

Because a finally block will always be called unless you call System.exit() (or the thread crashes).


b
bikz05

Concisely, in the official Java Documentation (Click here), it is written that -

If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.


A
Ankush soni

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

M
Meet Vora

Answer is simple YES.

INPUT:

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

OUTPUT:

catch
finally

Answer is simple NO.
@ChristopheRoussy How? Can you explain please?
read the accepted answer, the original question is about 'Will it always execute' and it will not always. In your case it will but this does not answer the original question and may even be misleading beginners.
then in which case it wont get execute?
In all cases mentioned in other answers, see accepted answer with 1000+ upvotes.
A
Anonymous Coward

NOT ALWAYS

The Java Language specification describes how try-catch-finally and try-catch blocks work at 14.20.2
In no place it specifies that the finally block is always executed. But for all cases in which the try-catch-finally and try-finally blocks complete it does specify that before completion finally must be executed.

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).

The JLS does not guarantee that FIN is executed after CODE. The JLS guarantees that if CODE and NEXT are executed then FIN will always be executed after CODE and before NEXT.

Why doesn't the JLS guarantee that the finally block is always executed after the try block? Because it is impossible. It is unlikely but possible that the JVM will be aborted (kill, crash, power off) just after completing the try block but before execution of the finally block. There is nothing the JLS can do to avoid this.

Thus, any software which for their proper behaviour depends on finally blocks always being executed after their try blocks complete are bugged.

return instructions in the try block are irrelevant to this issue. If execution reaches code after the try-catch-finally it is guaranteed that the finally block will have been executed before, with or without return instructions inside the try block.


My apologies for commenting on such an old answer, but I don't think saying any software which for their proper behaviour depends on finally blocks always being executed after their try blocks complete are bugged. is quite right. finally blocks are usually used for resource clean-up to prevent leaks. How else would you do it? In the same vein, you cannot (or should not...) catch Errors either, as there is (usually) no reasonable way for a normal application to handle them.
@user991710 If clean-up in the finally block is in example about closing an open file then not executing the finally block is not a problem, the OS closes it on program termination. If clean-up is deletion of a file that is a problem, the OS won't do it when the program is aborted before finally. If another part of the system depends on the java program always doing such deletion then the system in general and the java program in particular are bugged. You can't rely on finally always executing. You can only rely on the guarantee that finally has already been executed if NEXT has been executed
Interesting take, although it forces some parts of your design as far as I can see. To expand on your deletion example: would you have a kind of 'reaper' task running that is responsible for deletion (clean-up) of files? I admit that, given your explanation, using finally may (given enough time, likely will) cause bugs, but is the additional development (and testing) time worth the potentially unnoticeable improvement in stability? More generally: does the amount of care that should go into a particular design depend on the subsystem in question? Time is a valuable resource, after all. :)
@user991710 There is nothing wrong with using finally. You just need to know what it does and what it does not. For the particular case of deleting a file I would actually do it in the finally block. But being aware that doing so provides no guarantee (not even if the last line of the try block finished executing) I would take precautions to deal which such situation. So deleting previous leftover files as a first step of executing the program, if this is a service style program which would be re-run automatically. If system failing in such situation is of no concern then, sure, don't bother
s
srk

finally block is always executed and before returning x's (calculated) value.

System.out.println("x value from foo() = " + foo());

...

int foo() {
  int x = 2;
  try {
    return x++;
  } finally {
    System.out.println("x value in finally = " + x);
  }
}

Output:

x value in finally = 3 x value from foo() = 2


Nice illustrative example, +1.
K
Karthikeyan

Yes, it will. No matter what happens in your try or catch block unless otherwise System.exit() called or JVM crashed. if there is any return statement in the block(s),finally will be executed prior to that return statement.


a
abhig

Yes It will. Only case it will not is JVM exits or crashes


G
Gautam Viradiya

Yes, finally block is always execute. Most of developer use this block the closing the database connection, resultset object, statement object and also uses into the java hibernate to rollback the transaction.


L
L Joey

finally will execute and that is for sure.

finally will not execute in below cases:

case 1 :

When you are executing System.exit().

case 2 :

When your JVM / Thread crashes.

case 3 :

When your execution is stopped in between manually.


N
Neuron

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


As of Java 1.8.162, this is not the output.
l
lue

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


See the accepted answer. This is just an edge case of "infinite loop".
s
sam

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.
    }
}

Shouldn't it be sb.setLength(0) in finally?
sb.setLength(0) will just empty the data in the StringBuffer. So, sb = null will disassociate the object from the reference.
Shouldn't "xyz" be printed twice in the output? Since the function was called twice, why "finally" was only once?
This isn't a good practice. That finally block with sb = null; just adds unneeded code. I understand that you mean that a finally block is a good place to free resources like a database connection or something like that, but have in mind that your example could confuse newcomers.
@Samim Thanks, I added the lines System.out.println("---AGAIN2---"); System.out.println(sb); and it's more clear now. As it was, the output was against your thesis :p I also added to your answer, but the edit must be accepted by a moderator or somebody like that. Else you can add them
S
Scott Dorman

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.


A
Alex Miller

In addition to the point about return in finally replacing a return in the try block, the same is true of an exception. A finally block that throws an exception will replace a return or exception thrown from within the try block.