0

Lets consider a test class

import java.util.Date;


public class TestClass {

    public String finallyHappensBeforeReturn(){
        try{
            return "Important Message";
        }finally{
            finallyHappensBeforeReturn();
        }
    }

    public String unaffectedReference(){
        String message = "Important msg";
        try{
            return message;
        }finally{
            message = " meaning of life";
        }
    }

    public Container modifiedReference(){
        Container c = new Container();
        c.set("Important msg");
        try{
            return c;
        }finally{
            c.set("Meaning of life");
        }
    }

    public void timer(){
        try{
            System.out.println("Try time = " + new Date().getTime());
        }finally{
            System.out.println("Finally time = " + new Date().getTime());
        }
    }

    class Container{
        String s;
        void set(String s){
            this.s = s;
        }

        String get(){
            return s;
        }
    }
}

If we create a main method as follows:

public static void main(String[] args){
    TestClass instance = new TestClass();
    instance.timer();
}

We can clearly see output that suggests that try happens before finally, like we would expect. Printing the time is kind of meaningless for most of us, since on my as well as most other machines the method will execute in less then a millisecond, but none the less I figured Id include it.

If we change the main to

public static void main(String[] args){
    TestClass instance = new TestClass();
    System.out.println(instance.unaffectedReference());
}

we get "Important msg" printed, which suggests unaffectedReference() returns a reference to String literal "Imporant msg", we print it to console, and only after that happens the pointer is changed to point to String object "Meaning of life". Makes sense so far.

However, if we change main to

public static void main(String[] args){
    TestClass instance = new TestClass();
    System.out.println(instance.modifiedReference().get());
}

we get "Meaning of life". Note, we do not keep a reference to the Container modifiedReference() returns. So, if it was

public static void main(String[] args){
    TestClass instance = new TestClass();
    Container container = instance.modifiedReference();
    System.out.println(container.get());
}

it would make sense. modifierReference() returns a reference, then goes into finally{}, changes the object the reference, well, references - and only then the value is printed. What happened there? finally executed before the System.out.print() but AFTER return? How is that possible?

And, one last example -

public static void main(String[] args){
    TestClass instance = new TestClass();
    System.out.println(instance.finallyHappensBeforeReturn());
}

In this case we get a StackOverflowError, which also suggests that finally happens before return. Note that "Important Message" is never printed before the exception is thrown.

So, the question is which came first - the finally or the return?

aiguy
  • 671
  • 5
  • 20
  • Also [Does finally always execute in Java?](http://stackoverflow.com/q/65035/1768232) and [When Does the Finally Block Run Relative to the Return](http://stackoverflow.com/q/20380869/1768232) – durron597 Aug 05 '15 at 04:24

1 Answers1

0

Doesn't have that much to do with what is executed after what (it's try, catch, return, finally - finally runs after return, but before the method actually returns, so it technically CAN modify the return value - you just shouldn't do that). The basic thing is to know that String is immutable.

   public String unaffectedReference(){
    String message = "Important msg";
    try{
        return message;
    }finally{
        message = " meaning of life";
    }
   }

This will return "Important msg", then change message (in the method) to " meaning of life". But the return value is a reference to the String "Important message" and not the "message". If String was NOT immutable and you were to do message.setValue(" meaning of life") for example, then this would be printed out.

 public Container modifiedReference(){
    Container c = new Container();
    c.set("Important msg");
    try{
        return c;
    }finally{
        c.set("Meaning of life");
    }
}

...your return value is a reference to the Container object and changing something INSIDE this Container object modifies the return value, of course, because you are return an object and this object gets modified.

Florian Schaetz
  • 10,454
  • 5
  • 32
  • 58
  • I used String specifically because it is immutable and a Container because it is not. I guess could have used Integer since it is as well, but hey. In the case with returning a Container in the 3rd example the question is why does System.out.println() not get invoked BEFORE the returned Container is modified? Like you said finally happens after the return statement but 'before the method actually returns' - thats the part Im unclear on. You would think after a method returns the next statement should get executed. – aiguy Aug 05 '15 at 04:42
  • As long as you are in finally, the method has not yet ended. The code does not jump around from the method to the executing point back to the method. It executes return, then the try block, then the method really ends and the system out is executed. – Florian Schaetz Aug 05 '15 at 04:47
  • So, to sum it up a when a return statement executes does not mean a method 'ended'. The return value is cached somewhere and can be overwriten (by another return in a finally block) or modified. Basically, finally executes after try regardless of where the method 'returns'? – aiguy Aug 05 '15 at 05:33
  • Basically correct, yes. A finally executes after the return, is able to return something else (but you shouldn't) or modify the return value (if not immutable - and again, most likely you shouldn't) but is still executed BEFORE finally (no pun intended) leaving the method. The next code outside the method is executed AFTER the finally. – Florian Schaetz Aug 05 '15 at 05:35