HuntExams Academy logo
JavaAdvanced#puzzle#exceptions

What does this code output and why? try { return 1; } finally { return 2; }

Answer

The finally block's return statement overrides the try block's return, so the method returns 2. This is a well-known gotcha — avoid returning from finally blocks in real code.

Example

int test() {
  try { return 1; } finally { return 2; }
}
System.out.println(test()); // Output: 2

Detailed explanation

The method returns 2, so System.out.println(test()) prints 2. The snippet by itself does not print anything; it determines the value returned by its enclosing method. When execution reaches return 1 in the try block, Java evaluates the return expression, but control does not immediately leave the method. The associated finally block must execute first. Because that block executes return 2, its return replaces the pending return from the try block.

Under Java's control-flow rules, a return statement is an abrupt completion: it transfers control rather than allowing execution to continue normally. The try block therefore completes abruptly with a pending return value of 1. Java then executes finally. If finally completes normally, the original return proceeds. However, if finally also completes abruptly, its reason for abrupt completion takes precedence. Here, finally completes with a return value of 2, discarding the earlier return. This is specified language behaviour, not a compiler optimisation or an unpredictable ordering issue.

A useful contrast is try { return x; } finally { x = 2; }, where x is a local int initially equal to 1. That method returns 1 because the return expression was evaluated before finally changed x. Returning an object reference follows the same evaluation rule: reassigning the local reference in finally does not replace the pending reference, although modifying the referenced object's fields can change the object the caller receives. In the original example, it is the second return statement—not merely executing finally—that changes the result.

Interviewers use this question to check whether you distinguish expression evaluation, cleanup execution, and actual control transfer. The practical danger goes beyond surprising return values: returning from finally can also suppress an exception thrown inside try, hiding a failure from the caller. Keep finally focused on cleanup without return statements, and use try-with-resources for suitable AutoCloseable resources. Also avoid saying finally runs under absolutely every circumstance: JVM termination, for example, can prevent its execution.

Key points to remember

  • test() returns 2; System.out.println(test()) prints 2.
  • The try block's return expression is evaluated before finally executes.
  • A normally completing finally preserves the pending return.
  • A return or thrown exception from finally replaces the pending return or exception.
  • Avoid returning from finally because it can obscure results and suppress failures.

Common mistakes candidates make

  • Claiming return 1 immediately exits the method and skips finally.
  • Assuming changing a local primitive variable in finally changes an already evaluated return value.
  • Treating return from finally as harmless cleanup, overlooking its ability to suppress exceptions.

Likely follow-up questions

What happens if finally contains only a print statement?

If the print statement completes normally, the method returns 1. The message from finally is printed before the caller receives the return value.

What if try throws an exception but finally returns 2?

The method returns 2, and the exception from try does not propagate to the caller. This can hide a failure, making return statements in finally particularly dangerous.

What if try returns 1 but finally throws an exception?

The method throws the exception from finally instead of returning 1. The pending return is discarded because finally completes abruptly by throwing.

Interview tip: State that the output is 2, explain the pending return being replaced, and finish by warning against returning from finally.

Related Interview Questions

1
JavaAdvanced#puzzle#collections

What is the output? List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); for (Integer i : list) { if (i == 1) list.remove(i); }

Open
2
JavaIntermediate#puzzle#oop

What is the output of this code involving static and instance initialization order? class A { static { System.out.println("static A"); } { System.out.println("instance A"); } A() { System.out.println("constructor A"); } } new A(); new A();

Open
3
JavaIntermediate#puzzle#fundamentals

What does this print? Integer a = 127; Integer b = 127; Integer c = 128; Integer d = 128; System.out.println(a == b); System.out.println(c == d);

Open