2

As per the answer here, it is stated that if we have return statement inside the try/catch block then before executing the return statement finally block will be executed.

But I am seeing some unexpected output for the below code:

Output

In try block, value is : 20

In finally block, value is : 40

In main method, value is : 20

Before returning value from the try block, the value of 'x' is set to 40 in finally. But this is returning x's value as 20 instead of 40, to main method.

Can someone please explain, how is it working internally?

class ExceptionTest
{
private static int returnValue() {
    int x = 10;
    try {
        x=20;
        System.out.println("In try block, value is : " + x);
        return x;
    } 
    finally {
        x = 40;
        System.out.println("In finally block, value is : " + x);
    }
}
public static void main (String[] args) throws java.lang.Exception
{
    System.out.println("In main method, value is : " + returnValue());
}

}

Community
  • 1
  • 1
Ankit
  • 99
  • 6
  • you don't return from `finally`, that's why the variable remains with value assigned in `main`. if you return it from `finally` as well, it's going to be 40 – mangusta Sep 24 '19 at 18:08
  • 1
    I swear I saw the _exact_ same question here like a week ago. – Nexevis Sep 24 '19 at 18:08
  • @mangusta by you *shouldn't* return (or throw) from a finally block. – Andy Turner Sep 24 '19 at 18:08
  • @AndyTurner I know that I shouldn't, I never mentioned that I should – mangusta Sep 24 '19 at 18:09
  • 2
    Yup [here](https://stackoverflow.com/questions/57929659/why-return-is-not-honoring-the-value-of-variable-in-finally-block) is the question. Exact same scenario. Basically changing the value of `x` will not change the value of the return on `x` already called. – Nexevis Sep 24 '19 at 18:09
  • @mangusta you say "if you return from finally", without any qualification as to what a bad idea that would be. – Andy Turner Sep 24 '19 at 18:10
  • @AndyTurner the OP did not ask about how bad or good something should be, I told him how it works, all other judgement is up to the OP – mangusta Sep 24 '19 at 18:11
  • @mangusta I am not concerned about how it would behave with return in finally. I debugged the code and found that after executing the finally block when control went back to return statement of the try block, the values of variable x was set 40 at that moment [I put a watch on this variable]. – Ankit Sep 24 '19 at 18:21
  • @Ankit It doesn't matter what `x` is at that point, the `return` statement had already decided what value it was going to use the first time. No matter what do you to `x` in the other block it will still return `20` – Nexevis Sep 24 '19 at 18:27
  • @Nexevis is this statement false? -- "if we have return statement inside the try/catch block then before 'executing the return statement' finally block will be executed." Can you please explain where and how the return is holding the previous value of the variable 'x'? – Ankit Sep 24 '19 at 18:38
  • 2
    That statement is true, it is still executing the finally, but this `finally` block _only_ changes the value of `x`. The `return` already used `x` to get the value it needs! It will not look at `x` again. After the finally is done executing, the `return` will "finish" bringing the value back from before. If you did `return x` in the finally block _then_ the value would be overwritten, because the `return` itself is overwritten. The `return` returns the _value_ not the _variable_, maybe this is why you are confused. – Nexevis Sep 24 '19 at 18:40
  • 1
    @Ankit the key thing is that return statements return the value of an *expression*, not a variable. You can write `return 1;` or `return someMethod();`. The results of these aren't stored in a variable (they are just held on the stack), so there is no chance for their return value to be updated by doing something in the finally. It would be strange and inconsistent if `return x;` were any different. – Andy Turner Sep 24 '19 at 18:43
  • @AndyTurner you are absolutely write because at the very first time the value of the return statement has been written to stack there won't be any effect of overriding the variable, thank you. – shankar upadhyay Sep 25 '19 at 04:13

1 Answers1

1

This is described in JLS 14.20.2, "Execution of try-finally and 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:

Your try block doesn't complete normally, it completes abruptly at the return, so this doesn't apply.

  • If execution of the try block completes abruptly because of a throw of a value V, then there is a choice:

You don't throw, so this doesn't apply either.

  • If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and then there is a choice:

This applies.

  • If the finally block completes normally, then the try statement completes abruptly for reason R.

Your finally block completes normally (you don't return or throw from the finally - and it would be bad practice to do so), so your try statement completes for the reason R.

That R is that you returned the value of x when the expression of the return statement was evaluated.

You can find this in JLS 14.17:

A return statement with an Expression attempts to transfer control to the invoker of the method or lambda body that contains it; the value of the Expression becomes the value of the method invocation. ... 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.

It doesn't matter that you subsequently overwrite it: the reason R ("return with value V") is determined before executing the finally, so this is the reason why the finally block completes abruptly too.

Community
  • 1
  • 1
Andy Turner
  • 137,514
  • 11
  • 162
  • 243