When finally Does NOT Execute — Every Edge Case in Java
Fast recall
Quick revision
Core answer
finally runs in almost every case — normal completion, caught exceptions, uncaught exceptions, even return/break/continue from inside try. It is skipped in five cases: (1) System.exit(n) in try or catch, (2) the JVM crashes (OS kills it, kill -9, hardware failure), (3) an infinite loop or deadlock in try, (4) Thread.stop() / daemon-thread termination when JVM exits, (5) a fatal error like OutOfMemoryError triggers an unhandled JVM shutdown. A thrown exception inside finally also silently overrides any exception from try — the original is lost unless you capture it explicitly.Whether the candidate knows `finally` isn't an absolute guarantee — specifically the `System.exit`, JVM crash, and infinite-loop cases — and understands that exceptions thrown inside `finally` mask the original exception
Claiming `finally` always executes. Missing the exception-masking trap where `finally` throwing swallows the try block's exception. Not knowing `System.exit` skips finally even in caught branches
Mention the original-exception-masking bug and how try-with-resources fixes it via `addSuppressed()`. Explain why returning from `finally` is an anti-pattern (it replaces the try block's return value, including when try was throwing)
Interview-ready guide
Interview answer
The textbook says finally always runs — the interview answer is "almost always, and here are the cases it doesn't."
Cases where `finally` is skipped
System.exit(n)in the try or catch — JVM shuts down before finally runs; this is the classic gotcha- JVM crash —
kill -9, segfault, hardware failure, power loss - Infinite loop or deadlock inside try — control never leaves, so finally never starts
- Daemon thread still in try when JVM exits — daemon threads are killed abruptly
- Some fatal errors like
OutOfMemoryErrorin worst-case shutdown paths — implementation-dependent
The hidden trap — even when finally runs, it can destroy the original exception
- If the try block throws an
IOExceptionandfinallythen throws aRuntimeException, the caller sees only the RuntimeException — the IOException is lost returnfromfinallyis worse — it replaces both the return value and any in-flight exception from try- Every style guide flags
returnandthrowinside finally as bugs
What try-with-resources fixes
- The original body exception propagates; the close exception is attached via
addSuppressed()and retrievable withgetSuppressed() - Manual try-finally doesn't do this — you have to capture the original and rethrow it yourself
Recommendation: Use try-with-resources as the default for anything implementing AutoCloseable. Reserve manual finally for non-closeable cleanup like releasing a ReentrantLock, clearing MDC, or stopping a metric timer — and never return or throw from inside a finally block.
When `finally` Does NOT Execute — Every Edge Case in Java
Direct Answer
finally runs in almost every case — normal completion, caught exceptions, uncaught exceptions, even return/break/continue from inside try. It is skipped in five cases: (1) System.exit(n) in try or catch, (2) the JVM crashes (OS kills it, kill -9, hardware failure), (3) an infinite loop or deadlock in try, (4) Thread.stop() / daemon-thread termination when JVM exits, (5) a fatal error like OutOfMemoryError triggers an unhandled JVM shutdown. A thrown exception inside finally also silently overrides any exception from try — the original is lost unless you capture it explicitly.
Common Mistakes & Pitfalls
Claiming finally always executes. Missing the exception-masking trap where finally throwing swallows the try block's exception. Not knowing System.exit skips finally even in caught branches
Check your understanding
Answer these without looking back at the article.
- What happens if you `return` a value from both the try block and the finally block — which one wins?
- Why does `System.exit()` skip finally but a normal `return` does not?
- How does try-with-resources fix the exception-masking problem that manual try-finally has?
- Does `finally` execute if the try block calls `Thread.currentThread().interrupt()`?
- What are shutdown hooks and when do they run relative to finally blocks?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.