finally in Java
Always runs (except System.exit/JVM crash); return in finally overrides.
return 1; — yet the caller receives 2. No bug in the JVM. Just a finally block doing exactly what it was told.The cleanup crew
A **finally block runs after the try (and any catch) no matter how it ended**: normally, with an exception, or through return, break or continue. That makes it the place for cleanup, like releasing a lock.
lock.lock();
try {
update();
} finally {
lock.unlock(); // always runs
}Return, then finally?
What does this print?
String f() {
try {
System.out.print("T");
return "R";
} finally {
System.out.print("F");
}
}
void main() { System.out.println(f()); }TFRTRFTRFTR
Show the answer
return "R" is paused: finally runs first and prints F, then the method returns and main prints R.
Changing the answer late
finally changes n after return n. What prints?
int count() {
int n = 10;
try {
return n;
} finally {
n = 20;
}
}
void main() { System.out.println(count()); }1020Compile error
Show the answer
return n evaluates and saves the value (10) before finally runs. Changing n afterwards doesn't touch the saved result.
Only a dead JVM skips it
finally is skipped only when the JVM stops: **System.exit()** inside the try halts everything without returning normally, so finally never runs. A JVM crash or a killed process skips it too. Otherwise — it runs.
return inside finally
A return in finally replaces the pending return from try — try { return 1; } finally { return 2; } returns 2. Worse, it discards an in-flight exception: below, the caller gets 7 and the error silently vanishes. Never return from finally.
int risky() {
try {
throw new IllegalStateException();
} finally {
return 7; // exception lost!
}
}Locks, connections, timers
Forgetting to release a lock in finally can freeze a whole server when one request fails; forgetting to return a database connection slowly drains the pool until every request hangs. Cleanup belongs in finally (or try-with-resources, coming soon).
Key takeaways
- Runs after normal completion, exceptions, return, break and continue
- Skipped only by System.exit() or the JVM dying
- A return in finally replaces the pending return or exception
- The try's return value is computed before finally runs
javac can catch the dangerous pattern for you: compile with -Xlint:finally and it warns "finally clause cannot complete normally".
Practice questions
What does this print?
int test() {
try {
return 1;
} finally {
return 2;
}
}
void main() {
System.out.println(test());
}- 2
- 1
- 1 2
- Compile error
Check your answer
2. The try's return 1 is pending when finally runs; finally's own return replaces it.
What does this print?
int test() {
int x = 1;
try {
return x;
} finally {
x = 99;
}
}
void main() {
System.out.println(test());
}- 1
- 99
- Compile error
Check your answer
1. return x evaluates x (1) and saves that value before finally runs. Changing x afterwards doesn't change the saved result.