Why do we use finally blocks?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A finally block exists so that cleanup code can run whether an operation succeeds, fails, or returns early. It is most useful when some resource or side effect must be handled consistently, such as closing a stream, releasing a lock, or restoring temporary state.
What finally Guarantees
In a try-catch-finally structure, the finally block runs after the try and after any matching catch, even if:
- an exception was thrown
- an exception was caught
- the method returns from inside
tryorcatch
That makes finally the traditional place for cleanup code that must happen no matter what.
Calling demo() prints both lines because the return does not skip finally.
The Classic Use Case: Cleanup
Imagine opening a resource manually. You want to make sure it is closed whether the work succeeds or an exception interrupts it.
The key benefit is predictability. You do not have to remember to close the file on every code path separately.
Why finally Is Better Than Duplicating Cleanup
Without finally, people often write the same cleanup logic in multiple branches:
- one close call in the success path
- another in an error path
- maybe a third after some conditional return
That repetition is fragile. One branch eventually forgets the cleanup, and the bug only appears under specific error conditions.
finally centralizes the cleanup rule in one place.
Modern Java Often Uses Try-With-Resources Instead
In modern Java, finally is still important to understand, but many resource-management cases are better expressed with try-with-resources.
This is usually cleaner than a manual finally for closeable resources. The language guarantees the resource is closed automatically.
So the practical rule is:
- use try-with-resources for
AutoCloseableresources - use
finallyfor other cleanup that still must happen unconditionally
Other Good Uses for finally
finally is not limited to file handles. It is also useful for:
- unlocking a lock
- resetting thread-local or global state
- stopping a timer or tracer span
- restoring a UI or transaction flag
A locking example:
The unlock() call belongs in finally because forgetting it on an exception path can cause deadlocks.
What finally Does Not Guarantee
Developers sometimes overstate what finally can do. It is very reliable inside normal program execution, but it does not protect against every possible termination mode.
Examples where it may not run as you expect include:
- the process is forcibly killed
- the JVM crashes
- '
System.exit()terminates the process before normal flow continues'
So finally is a control-flow guarantee inside the program, not a universal protection against all external failure modes.
Common Pitfalls
One common mistake is writing cleanup in both catch and finally. That can duplicate work or introduce inconsistent behavior.
Another is throwing a new exception from finally without care. That can hide the original exception and make debugging much harder.
People also sometimes keep using manual finally blocks for closeable resources even when try-with-resources would be simpler and safer.
Finally, finally should be for cleanup, not for ordinary business logic. If the block starts doing core application work, the control flow becomes harder to reason about.
Summary
- '
finallyexists so cleanup code runs whether the protected work succeeds or fails.' - It is traditionally used for releasing resources, unlocking locks, and restoring state.
- In Java,
finallystill runs even iftryreturns early. - Try-with-resources is often the better modern choice for closeable resources.
- '
finallyis reliable for program control flow, but not for every kind of external process termination.'

