I have a simple Java class as shown below:
public class Test {
private String s;
public String foo() {
try {
s = "dev";
return s;
}
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
}
}
And the output of this code is this:
Entry in finally Block
dev
Why is s
not overridden in the finally
block, yet control printed output?
The try
block completes with the execution of the return
statement and the value of s
at the time the return
statement executes is the value returned by the method. The fact that the finally
clause later changes the value of s
(after the return
statement completes) does not (at that point) change the return value.
Note that the above deals with changes to the value of s
itself in the finally
block, not to the object that s
references. If s
was a reference to a mutable object (which String
is not) and the contents of the object were changed in the finally
block, then those changes would be seen in the returned value.
The detailed rules for how all this operates can be found in Section 14.20.2 of the Java Language Specification. Note that execution of a return
statement counts as an abrupt termination of the try
block (the section starting "If execution of the try block completes abruptly for any other reason R...." applies). See Section 14.17 of the JLS for why a return
statement is an abrupt termination of a block.
By way of further detail: if both the try
block and the finally
block
of a try-finally
statement terminate abruptly because of return
statements, then the following rules from §14.20.2 apply:
If execution of the
try
block completes abruptly for any other reason R [besides throwing an exception], then thefinally
block is executed, and then there is a choice:
- If the
finally
block completes normally, then thetry
statement completes abruptly for reason R.- If the
finally
block completes abruptly for reason S, then thetry
statement completes abruptly for reason S (and reason R is discarded).
The result is that the return
statement in the finally
block determines the return value of the entire try-finally
statement, and the returned value from the try
block is discarded. A similar thing occurs in a try-catch-finally
statement if the try
block throws an exception, it is caught by a catch
block, and both the catch
block and the finally
block have return
statements.