How do try, catch and finally interact in Java, and in what exact order do they run?
The rules are precise. A try block is followed by zero or more catch blocks and then, optionally, a finally block. The catch blocks are tried in order, and the first one whose type matches the thrown exception handles it. The finally block, if there is one, runs after the try body completes normally or after a catch block handles an exception — in both cases, and also when an exception is not caught at all and is on its way out.
The order in practice: the try body runs first. If it throws, the matching catch runs. Then finally runs. If the try body completes normally, the catch blocks are skipped entirely and finally runs. If no catch matches, the exception propagates, but finally still runs first — and if finally completes normally, the original exception continues on its way.
public class Main {
public static void main(String[] args) {
System.out.println("result: " + compute(true));
System.out.println("result: " + compute(false));
}
static int compute(boolean fail) {
try {
System.out.println(" try");
if (fail) {
throw new IllegalStateException("boom");
}
return 1;
} catch (IllegalStateException e) {
System.out.println(" catch: " + e.getMessage());
return 2;
} finally {
System.out.println(" finally");
}
}
}The output shows the two paths clearly. In the first call the try block throws, the catch block handles it and returns 2, and the finally block still runs before the method returns. In the second call the try block completes normally, so the catch block is skipped entirely, the finally block runs, and the method returns 1.
That last point is the one people miss: the catch block is not a mandatory step. A return inside try does not skip finally — the finally block runs first, and only then does the method return. This is why finally is the right place for cleanup that must happen on every path.