33

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?

6
  • 1
    Why don't you add a System.out.println() to the finally block and see yourself? I think it is executed but the value returned is 1. Commented Aug 8, 2013 at 16:41
  • When using try catch, you can "catch" specific types of exceptions (eg: IOException, NullPointerException etc..) the finally statement occurs when the specific exception happens and you need to run some code before the catch anyways... Commented Aug 8, 2013 at 16:44
  • 7
    Here's something to think about while upvoting Commented Aug 8, 2013 at 16:44
  • 1
    @RicardoE - Not exactly correct. The finally clause is (short of some messy recursive exception cases) always executed, if the try region is entered. Commented Aug 8, 2013 at 16:45
  • 1
    @Keyser Because of answers from people like Rohit who take the time to actually explain what's happening and all of the underlying functionality, in order that everyone, not just the asker, can go forth with a much more comprehensive understanding. Commented Aug 8, 2013 at 16:54

3 Answers 3

29

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:

Sign up to request clarification or add additional context in comments.

4 Comments

Adding to this: Only the return value itself is stored on the stack. If you are returning a reference to an object, modifications to the object's fields done in the finally block will still be visible.
@JasonC. Yup true. Will add to the answer. Thanks :)
And if anyone's confused about why builder = null doesn't nullify the return value it's because of the pass by value thing.
@Keyser. Yes exactly that.
12

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

1 Comment

Well, I suppose someone had to actually read the documentation. Every party has a pooper.
0

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

1 Comment

I think that misses the point.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.