16
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
RAS
  • 8,100
  • 16
  • 64
  • 86
Harinder
  • 11,776
  • 16
  • 70
  • 126

7 Answers7

27

That's because you returned a value that was evaluated from q before you changed the value of q in the finally block. You returned q, which evaluated its value; then you changed q in the finally 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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • but the value gets returned after the finally block is executed.. so – Harinder Jun 25 '12 at 10:09
  • 1
    @Dennis The value to return was loaded before the finally block was executed. I already said that. – user207421 Jun 25 '12 at 10:14
  • 1
    @Dennis yes, but in `finally` you are already _past_ the `return` instruction, not immediately before it. – maksimov Jun 25 '12 at 10:15
  • 1
    thanks a lot, just posted this question for a knowledge update, and no i wont be writing such code.. – Harinder Jun 25 '12 at 10:17
  • Just to add: When returning an object, the reference to the object is returned. So assigning variable to a different String in finally block doesn't affect the return value. – nhahtdh Jun 25 '12 at 10:18
  • @EJP...but when we return from finally block as ria suggested above..we get the value which is set in finally...how come it's possible..?.. – Ahmad Jun 25 '12 at 10:23
  • @Ahmad Because the `return` statement in a `finally` block executes after everything else, i.e. `finally`. – user207421 Jun 25 '12 at 10:26
  • @EJP..please check my new answer..and verify it – Ahmad Jun 26 '12 at 06:42
  • @Ahmad I don't know why you are just repeating my answer in comments under it, or why you are asking me under my answer to review your answer which you have edited based on my answer. If your answer agrees with mine it is correct. You can't seriously expect me to say anything else, can you? – user207421 Aug 01 '12 at 21:44
  • @EJP...well actually it was not based on your answer .I have done experiments and wrote their results.I eventually missed to read your answer and posted my comment. Sorry anyways.. – Ahmad Aug 02 '12 at 07:31
  • @Ahmad If your answer is based on independent experiment you don't need me to confirm it. If it contradicts mine, I am obviously going to say so; if it is the same as mine I am obviously going to confirm it, so you don't need to ask: you just need to decide whether it is the same. I don't understand why you need me to get involved in this at all in either case. – user207421 Sep 19 '12 at 10:36
4

return returns value not variable. When return q; gets executed in catch section value of q variable is cached as method result. It is like method remembers current value of q, but before it returns it also lets us finallize some things.

So even if in finally block you will assign new value to q it will not change already value cached by method.

If you want to update returned value you will have to use another return in finally block like

} finally {
    q = "hello";
    System.out.println("finally value of q is " + q);

    return q; // <--- this will set new value which should be returned
}

Other way of affecting returned "value" is changing its state.

For instance if q was a List you could add new element to it in finally block

} finally {
    q.add(new Element); //this will place new element (update) in List 
    //object stored by return because it is same object from q reference
    System.out.println("finally value of q is " + q);
}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • 'Value (object) +from+ reference, not exact reference', 'read/store object from reference', and 'object stored in return' are meaningless. Not an answer. There's probably an answer in here struggling to get out, but the terminology is so confused that no meaning is conveyed. – user207421 Aug 01 '12 at 21:52
2

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.

John Watts
  • 8,717
  • 1
  • 31
  • 35
0

[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

A try statement with a finally block is executed by first executing the try block. Then there is a choice:

If execution of the try block completes normally, then the finally block is executed, and then there is a choice:
If the finally block completes normally, then the try statement completes normally.
[...]

and JLS 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. More precisely, execution of such a return statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the return statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the return statement completes abruptly, the reason being a return with value V

And:

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 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.

Community
  • 1
  • 1
pgras
  • 12,614
  • 4
  • 38
  • 46
0

Try using StringBuffer instead of String and you will see the change .... it seems the return statement blocks the object which is to be returned and not the reference. You could also try to verify this by printing the hashcode of :

  • object being returned from go()
  • object in finally
  • object being printed from main()

    public static void main(String[] args){

        Test obj=new Test();
            StringBuffer a=obj.go();
            System.out.print(a);
        }
      public StringBuffer go() {
            StringBuffer q=new StringBuffer("hii");
            try {
                return q;
            }
            finally {
                q=q.append("hello");
                System.out.println("finally value of q is "+q);
            }
        }
    
Twaha Mehmood
  • 737
  • 3
  • 9
  • 26
0

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.

Reachgoals
  • 2,151
  • 2
  • 15
  • 9
-1

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.

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

the output of the program is

finally value of q is hello

hii

and if we take StringBuffer instead of String as follows,

public class Test2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Test2 obj=new Test2();
        StringBuffer a=obj.go();

        System.out.print(a);
    }


    public  StringBuffer go(){
        StringBuffer q=new StringBuffer("hii");
        try{

            return q;
        }
        finally{

            q.replace(0, q.length(), "hello");
            System.out.println("finally value of q is "+q);
            /*return q1;*/

        }

    }
}

The output comesout to be,

finally value of q is hello

hello

and finally if we take int instead of String as follows,

public class Test2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Test2 obj=new Test2();
        int a=obj.go();

        System.out.print(a);
    }


    public  int go(){
        int q=1;
        try{

            return q;
        }
        finally{

            q=2;
            System.out.println("finally value of q is "+q);
            /*return q1;*/

        }

    }
}

the output is

finally value of q is 2

1

                              **Ananlysis**

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.

Ahmad
  • 2,110
  • 5
  • 26
  • 36
  • Your first two examples are both irrelevant. The first one is just plain wrong code, as String.repace() doesn't mutate the value, it returns a new one which you are throwing away. The second one does mutate the value, but as that's not what the OP is doing I fail to see the point. The third one just reiterates what the OP is asking about, and repeats the answer that had already been given. – user207421 Jun 26 '12 at 12:59