Detailed explanation
In Java, execution starts with the try block. If it completes normally, all catch blocks are skipped and finally executes. If a statement throws an exception, the remaining statements in try are skipped, and Java selects the first catch whose parameter type can handle that exception. Only one catch executes; finally then runs. For example, if try prints A and throws an IllegalStateException, its matching catch prints B, and finally prints C, the output order is A, B, C.
Catch blocks are checked in their written order, so a more specific exception type must appear before a superclass type that would also catch it. Otherwise, the later catch is unreachable and compilation fails. If no catch matches, finally executes before the exception propagates outward. An exception thrown inside a catch is not handled by another catch attached to the same try. It also passes through finally before propagating. Code after the complete statement runs only when control reaches it normally, not when a return or exception carries control elsewhere.
Finally also executes before a pending return, break, or continue completes, provided control leaves the associated try or catch. With return x, Java evaluates and saves the return value before executing finally. For example, if x is 1 when return x executes, assigning x = 99 inside finally still leaves the returned integer as 1. For an object reference, however, finally can mutate the referenced object's contents. A return or exception from finally replaces the pending return or exception, potentially hiding the original failure; avoid such control flow.
Finally is intended for cleanup, but it is not an unconditional guarantee: JVM termination through System.exit, a process crash, or code that never exits try can prevent execution. Ordinary exception propagation, including many Errors, still executes finally. For AutoCloseable resources, prefer try-with-resources: successfully initialized resources close in reverse initialization order before associated catch and finally blocks run. If the body throws and closing also fails, the closing failure is suppressed on the primary exception. A try-finally statement without catch is also legal.
Key points to remember
- Normal execution: try → finally → following code.
- Handled exception: try until failure → first matching catch → finally.
- Unhandled exception: try until failure → finally → propagation to an outer handler.
- A pending return value is evaluated before finally; finally can override pending control flow.
- Use try-with-resources for automatic resource closing, and put specific catch types before general ones.
Common mistakes candidates make
- Saying finally always runs without acknowledging JVM termination or a try block that never exits.
- Assuming every catch executes, or that sibling catch blocks handle exceptions thrown by one another.
- Returning from finally or allowing cleanup exceptions to mask the original exception.
Likely follow-up questions
Does changing a variable in finally change the returned value?
Not if the return expression has already evaluated to a primitive value: return x saves that value before finally runs. If the saved value is an object reference, mutating that object's fields in finally can affect what the caller observes, but reassigning the local reference does not.
What happens if both try and finally throw exceptions?
The exception thrown by finally propagates, replacing the original exception. Unlike try-with-resources, ordinary finally does not automatically preserve the original failure as a suppressed exception.
What if close() fails in try-with-resources?
If the body already threw an exception, that remains the primary exception and closing failures are attached as suppressed exceptions, accessible through getSuppressed(). If there is no pending exception, the first closing failure becomes the primary exception, and subsequent closing failures are suppressed.
Interview tip: Explain the normal and exceptional sequences first, then demonstrate the saved return-value rule with a small integer example.
