java: try finally blocks execution [duplicate]

2019-01-15 05:57发布

问题:

This question already has an answer here:

  • Does a finally block always get executed in Java? 46 answers
  • Strange finally behaviour? 7 answers

I am confused about the try-finally execution when there exists return; in the try block. In my understanding, the finally block will always be executed, i.e. before returning to the calling method. While considering the following simple code:

public class TryCatchTest {
    public static void main(String[] args){
        System.out.println(test());
    }
    static int test(){
        int x = 1;
        try{
            return x;
        }
        finally{
            x = x + 1;
        }
    }
}

The result printed is actually 1. Does this mean the finally block is not executed? Can anyone help me with it?

回答1:

When you return from try block, the return value is stored on the stack frame for that method. After that the finally block is executed.

Changing the value in the finally block will not change the value already on the stack. However if you return again from the finally block, the return value on the stack will be overwritten, and the new x will be returned.

If you print the value of x in finally block, you will get to know that it is executed, and the value of x will get printed.

static int test(){
    int x = 1;
    try{
        return x;
    }
    finally{
        x = x + 1;
        System.out.println(x);  // Prints new value of x
    }
}

Note: In case of a reference value being returned, the value of reference is stored on the stack. In that case, you can change the value of object, using that reference.

StringBuilder builder = new StringBuilder("");
try {
    builder.append("Rohit ");
    return builder;

} finally {
    // Here you are changing the object pointed to by the reference
    builder.append("Jain");  // Return value will be `Rohit Jain`

    // However this will not nullify the return value. 
    // The value returned will still be `Rohit Jain`
    builder =  null;
}

Suggested Read:

  • JVM Specs - Frames


回答2:

The finally block is executed. The local variable is incremented. But the value of that local variable has already been copied for the return value.

From the Java Language Specification, 14.17: The return statement:

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 (§14.20) within the method or constructor whose try blocks or catch clauses 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



回答3:

You are returning x before you exit try. I would do this:

public class TryCatchTest {
    public static void main(String[] args) {
        System.out.println(test());
    }
    static int test() {
        int x = 1;
        try {
            do something with x.
        } finally {
            do something that will happen even in case of error;
            x = x + 1;
            return x;
        }
    }
}