Do you know what value will be printed when following program is ran?
class Test { public int aaa() { int x = 1; try { return ++x; } catch (Exception e) { } finally { ++x; } return x; } public static void main(String[] args) { Test t = new Test(); int y = t.aaa(); System.out.println(y); } }
And before answering the above question, do you have answers to following questions?
- If there is a return statement in try block, will the finally block be executed when the return is executed?
- If finally will be executed, do you know how this is achieved so that both return and finally will be executed?
If you don't know the answers to above questions, please continue to read.
According to Oracle Java tutorial, there is an explanation about this special case where there is return in try block and a finally block also exists.
The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
Note: 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.
Above explains that finally will always be executed no matter whether there is a return, break or continue statement in try block. The only exceptions are that the JVM exits or some interruptions to the thread which executes the try finally block. This means if you call System.exit(0) in try block, finally block will not be executed.
So what will be the output of above code? The answer is 2 instead of 3. Why? The JVM specification has given the answer.
If the try clause executes a return, the compiled code does the following:
- Saves the return value (if any) in a local variable.
- Executes a jsr to the code for the finally clause.
- Upon return from the finally clause, returns the value saved in the local variable.
When return ++x is executed, JVM will put the value of ++x into a temp variable and it will continue to execute the finally block. After finally is executed, the value stored in the temp variable will be returned to the caller of the method. Hence the output will be 2 but not 3.
The javap output of the Test.class will also show this.
The command operation orders are:
- iconst_1 : Push constant 1 into the stack
- istore_1 : Pop the value in the stack and then store it to the local variable table at position 1
- inc 1, 1 : Increment the local variable at position 1 by 1
- iload_1 : Push the local variable at position 1 into the stack
- istore_2 : Pop the value in the stack and then store it to the local variable table at position 2
- inc 1, 1 : Increment the local variable at position 1 by 1
- iload_2 : Push the local variable at position 2 to the stack
- ireturn : Return the value popped from the stack(2 here)
- ...
One thing to note is that the return value of the finally block will be the one returned to the caller of the method if there is a return statement in the finally block as well. This is because the specification says that the return in try will be ignored and the return in finally will the one returned if both try and finally have return statement.
Reference : http://www.cnblogs.com/averey/p/4379646.html
If you move last return into finally, the output is 3.