88

By reading all the questions already asked in this forum related to the topic above (see title), I thoroughly understand that finally gets always called. (except from System.exit and infinite loops). However, I would like to know if a return is called in a catch block and then another return is called from the finally block.

For example:

public static void main(String[]args) {
    int a = new TestClass().absorbeTheValue();
}

int absorbeTheValue() {
    try {
        int a = 10/0;
        if (a > 0) return 4;
    } catch(Exception e) {
        return 45;
    } finally {
        return 34;
    }
}    

So here the output (when the method is called) is going to be 34 in any case. It means that finally always gets run. I think though that the other "returns" are not run at all. In many posts I found the fact that finally write the content over what had been already written by the catch clause return. My understanding is that as soon as the return value in the catch clause is about to be evaluated, the control flow pass to the finally clause which having in turn another return, this time the return will be evaluated without passing control back to the catch clause. In this way the only return called at runtime will be the finally return. Do you agree with that?

A return in finally does not pass back the control to the program but returns the value and terminates the method. Can we say so?

Lii
  • 11,553
  • 8
  • 64
  • 88
Rollerball
  • 12,618
  • 23
  • 92
  • 161

2 Answers2

132

If the return in the try block is reached, it transfers control to the finally block, and the function eventually returns normally (not a throw).

If an exception occurs, but then the code reaches a return from the catch block, control is transferred to the finally block and the function eventually returns normally (not a throw).

In your example, you have a return in the finally, and so regardless of what happens, the function will return 34, because finally has the final (if you will) word.

Although not covered in your example, this would be true even if you didn't have the catch and if an exception were thrown in the try block and not caught. By doing a return from the finally block, you suppress the exception entirely. Consider:

public class FinallyReturn {
  public static final void main(String[] args) {
    System.out.println(foo(args));
  }

  private static int foo(String[] args) {
    try {
      int n = Integer.parseInt(args[0]);
      return n;
    }
    finally {
      return 42;
    }
  }
}

If you run that without supplying any arguments:

$ java FinallyReturn

...the code in foo throws an ArrayIndexOutOfBoundsException. But because the finally block does a return, that exception gets suppressed.

This is one reason why it's best to avoid using return in finally.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • It's important to note that `throw` will be interchangeable with `return` for these purposes. (E.g., `throw new Exception(4)`, `throw new exception(34)`) – Marcus Aug 16 '13 at 23:53
  • I just want to chip in on what user1442960 said. The JLS says nothing about a return in a catch or a finally. It uses the term "abruptly", which I'm guessing means either an exception or a return. – Steve11235 Nov 18 '13 at 20:48
  • 1
    @Steve11235: No, a `return` from a `catch` block would be completing "normally," not "abruptly." This is reasonably clear from [Section 11](http://docs.oracle.com/javase/specs/jls/se8/html/jls-11.html): *"During the process of throwing an exception, the Java Virtual Machine abruptly completes, one by one, any expressions, statements, method and constructor invocations, initializers, and field initialization expressions that have begun but not completed execution in the current thread."* – T.J. Crowder Aug 09 '14 at 23:18
92

Here is some code that show how it works.

class Test
{
    public static void main(String args[]) 
    { 
        System.out.println(Test.test()); 
    }

    public static String test()
    {
        try {
            System.out.println("try");
            throw new Exception();
        } catch(Exception e) {
            System.out.println("catch");
            return "return"; 
        } finally {  
            System.out.println("finally");
            return "return in finally"; 
        }
    }
}

The results is:

try
catch
finally
return in finally
andre
  • 7,018
  • 4
  • 43
  • 75
  • 11
    +1 easy to understand and taught me something new :) – ldam Mar 05 '13 at 14:28
  • 1
    @LoganDam T.J. Crowder gives a very good explanation. – andre Mar 05 '13 at 14:31
  • 1
    @LoganDam: It is a nice clean explanation of the order of operations. However, it does not answer the question being asked. The question explicitly asks about what happens when a `finally` block contains a `return` statement. – unholysampler Mar 05 '13 at 14:33
  • And I've learned something new again... keep it up guys! – ldam Mar 05 '13 at 14:38
  • good case to test how control flow works . Very interesting – ShanJay Nov 23 '13 at 16:58
  • with "return" does it return to the next statement after 'try-catch-finally' ? or does it exit the function? You should add that to your example. – Nulik Jan 06 '17 at 15:32