Finally Block in Java
Some work must happen no matter what: closing a file you opened, releasing a lock, printing "done" in a log. If that cleanup sits after the try-catch, an unexpected exception or an early return can skip it. A finally block runs after the try (and any catch) in every normal case: when the try succeeds, when an exception is caught, when it isn't caught, and even when the try returns.
It Runs on Every Path
public class Always {
static void attempt(String input) {
try {
System.out.println("try: " + Integer.parseInt(input));
} catch (NumberFormatException e) {
System.out.println("catch: bad input");
} finally {
System.out.println("finally: always runs");
}
}
static int value() {
try {
return 1;
} finally {
System.out.println("finally: runs before the return");
}
}
public static void main(String[] args) {
attempt("42");
attempt("x");
System.out.println("value = " + value());
}
}try: 42
finally: always runs
catch: bad input
finally: always runs
finally: runs before the return
value = 1How it works
- With
"42",trysucceeds,catchis skipped, thenfinallyruns. - With
"x", the exception is caught, thenfinallyruns. - In
value(),return 1is about to leave the method, but Java runsfinallyfirst, then completes the return.
What finally Is For
Cleanup that must not be skipped:
| Resource | Cleanup in finally |
|---|---|
| A lock | lock.unlock() |
| A file or connection (old style) | reader.close() |
| A temporary setting | Restore the old value |
| Timing or logging | Record "finished" |
For files, streams and connections, try-with-resources is now better than finally (see "Try-With-Resources in Java"): it closes things automatically and handles errors during closing.
When finally Does Not Run
finally runs on every normal path, but not when the JVM itself stops:
| Situation | Does finally run? |
|---|---|
System.exit(...) called in try or catch | No: the JVM shuts down immediately |
The JVM crashes, or the process is killed (power cut, kill -9) | No |
An infinite loop or a deadlock inside try | No: try never finishes |
| The thread running it is a daemon thread and the program ends | Not guaranteed |
public class Exit {
public static void main(String[] args) {
try {
System.out.println("about to exit");
System.exit(0);
} finally {
System.out.println("this never prints");
}
}
}about to exitTwo Traps with return
public class Traps {
@SuppressWarnings("finally")
static int overrides() {
try {
return 1;
} finally {
return 2;
}
}
static int unchanged() {
int x = 10;
try {
return x;
} finally {
x = 20;
}
}
public static void main(String[] args) {
System.out.println(overrides());
System.out.println(unchanged());
}
}2
10How it works
- A
returninsidefinallyreplaces thetry's return value, and it would also swallow any exception thetrythrew. The compiler warns about it with-Xlint(silenced here with@SuppressWarningsto show the effect). - In
unchanged(), the value10is saved whenreturn xruns. Changingxinfinallydoesn't change what's returned.
Under the Hood
The JVM has no "finally" instruction. The compiler copies the finally code onto every way out of the try, and uses the method's exception table to route exceptions:
5: getstatic #13 // System.out
8: ldc #19 // String done <- finally copy 1 (after try)
...
18: getstatic #13 // System.out
21: ldc #19 // String done <- finally copy 2 (after catch)
...
29: getstatic #13 // System.out
32: ldc #19 // String done <- finally copy 3 (any other exception)
38: athrow
Exception table:
from to target type
0 5 15 Class java/lang/NumberFormatException
0 5 28 any
15 18 28 anyThe any rows send any other exception to the third copy, which runs the cleanup and then rethrows with athrow.
Interview Corner
Does finally always execute?
It executes after try and catch on every normal path: normal completion, a caught or uncaught exception, and return, break or continue inside try. It doesn't run if the JVM stops first, for example via System.exit, a crash or the process being killed, or if the try never completes, as in an infinite loop.
What happens if both try and finally have a return statement?
The return in finally wins: its value is returned, and any value or exception from the try block is discarded. That's why returning from finally is considered bad practice.
Practice
- Easy: Write a method that prints "Start", then divides two numbers inside
try, catchesArithmeticException, and prints "End" infinally. Call it with a zero and a non-zero divisor. - Harder: Inside a
forloop, put atrywithcontinuefor odd numbers and afinallythat prints the number. Predict the output, then run it.
Key Takeaways
Was this tutorial helpful?