public class Test2 {
public static void main(String[] args) {
Test2 obj=new Test2();
String a=obj.go();
System.out.print(a);
}
public String go() {
String q="hii";
try {
return q;
}
finally {
q="hello";
System.out.println("finally value of q is "+q);
}
}
Why is this printing hii
after returning from the function go()
, the value has changed to "hello" in the finally block?
the output of the program is
finally value of q is hello
hii
Well, what I found is as follows,
Return actually returns a value and its gets copied to
String a=obj.go();
, before execution goes to Finally.Lets verify it by following experiments.
the output of the program is
finally value of q is hello
hii
and if we take StringBuffer instead of String as follows,
The output comesout to be,
finally value of q is hello
hello
and finally if we take int instead of String as follows,
the output is
finally value of q is 2
1
1.In first case, return copied adress of String in variable a, then excecution goes to Finally where String is changed. But since in case of Strings, we can't manipulate any String a new String is constructed. So in variable a address of original string is saved, which gets printed.
2.In second case, return copied address of StringBuffer in variable a, and in finally this StringBuffer object is manipulated, rather creating new one. so the value which was stored in variable a also gets manipulated, that's seen in print statement.
3.In third case, value of int is copied in variable a, before execution goes to finally. and thus a gets value of 1. and then in finally we changed value of q which doesn't anyway change value of a.
What is finally block?
-By definition from Java "The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs."
So, it prints "finally value of q is hello" as soon as it exists the try block and goes to line System.out.print(a); and prints the value returned by method go().
If you have a debuggers like netbeans or eclipse, it can be analyzed by keeping the break point and waking through the code.
[Edited after comment from EJP, my first response did not answer question and was also wrong.]
Now my answer should be correct explaining that as the try block and the finally block completes normally q is returned. And the reason why the value "hii" is returned is explained in EJPs answer. I'm still looking for an explanation in the JLS.
Have a look at JLS 14.20.2 Execution of try-catch-finally
and JLS 14.17 The return Statement
And:
return
returns value not reference. Whenreturn q;
gets executed incatch
current value ofq
reference is cached by method as its result. So even if infinally
block you will reassignq
with new value it doesn't affect value already cached by method.If you want to update value which should be returned you will have to use another
return
in yourfinally
block likeOther way of affecting returned value is by changing state of cached object. For instance if
q
was aList
we could add new element to it (but notice that changing state is not the same as reassigning a new instance, just like we can change state offinal
variable, but we can't reassign it).That's because you returned a value that was evaluated from
q
before you changed the value ofq
in the finally block. You returnedq
, which evaluated its value; then you changedq
in thefinally
block, which didn't affect the loaded value; then the return completed, using the evaluated value.Don't write tricky code like this. If it confuses the guy who wrote it, imagine the problems it will cause the next guy, a few years down the track when you are somewhere else.
Finally executes after return but before the method actually returns to the caller. This is analogous to throw. It happens after throw and before exiting the block. The return value is already set in some register by reading the variable q. If q was mutable, you could mutate it in finally and you would see that change in the caller. Why does it work this way? For one, it probably is the least complicated to implement. Two, it gives you maximal flexibility. You can override the return value in finally with an explicit return. Preserving it by default lets you choose either behavior.