finally Block in Java – Explained with Examples
The finally block contains code that runs after a try block no matter how the try block ends: normally, with a caught exception, with an uncaught exception, or with return, break or continue. That makes it the classic place for clean-up work such as closing files, releasing locks and resetting state.
This tutorial shows every situation in which finally runs, how it interacts with return, the rare cases where it does not run, and why try-with-resources is often a better choice for closing resources.
1. Syntax
try {
// code that may throw
} catch (SomeException e) {
// optional handler
} finally {
// always runs
}
try {
// code
} finally {
// clean-up without catching anything
}
2. When the finally Block Runs
public class FinallyCases {
static void run(String label, int divisor) {
System.out.println(label);
try {
System.out.println(" try: result = " + (10 / divisor));
} catch (ArithmeticException e) {
System.out.println(" catch: " + e.getMessage());
} finally {
System.out.println(" finally: always runs");
}
}
public static void main(String[] args) {
run("Case 1: no exception", 2);
run("Case 2: exception caught", 0);
System.out.println("Case 3: exception NOT caught");
try {
try {
Object s = "text";
Integer n = (Integer) s; // ClassCastException, no matching catch
} finally {
System.out.println(" finally: runs before the exception leaves");
}
} catch (ClassCastException e) {
System.out.println(" handled further up: " + e.getClass().getSimpleName());
}
}
}
Case 1: no exception try: result = 5 finally: always runs Case 2: exception caught catch: / by zero finally: always runs Case 3: exception NOT caught finally: runs before the exception leaves handled further up: ClassCastException
| Situation | Order of execution |
|---|---|
| No exception | try → finally → code after |
| Exception caught | try (stops) → catch → finally → code after |
| Exception not caught | try (stops) → finally → exception leaves the method |
return, break or continue in try | finally runs before control actually leaves |
3. finally with return, break and continue
public class FinallyAndReturn {
static String withReturn() {
try {
return "value from try";
} finally {
System.out.println("finally runs before the method returns");
}
}
@SuppressWarnings("finally")
static String overridingReturn() {
try {
throw new IllegalStateException("important error");
} finally {
return "finally wins"; // BAD: hides the exception
}
}
public static void main(String[] args) {
System.out.println(withReturn());
System.out.println(overridingReturn() + " (the exception was silently lost)");
for (int i = 1; i <= 3; i++) {
try {
if (i == 2) continue;
if (i == 3) break;
System.out.println("loop body " + i);
} finally {
System.out.println("finally for i=" + i); // runs on continue and break too
}
}
}
}
finally runs before the method returns value from try finally wins (the exception was silently lost) loop body 1 finally for i=1 finally for i=2 finally for i=3
- When
tryreturns a value, the value is computed first, thenfinallyruns, then the method returns. finallyalso runs when a loop iteration ends withcontinueorbreak.- Never return or throw from a finally block. As
overridingReturn()shows, areturninfinallyreplaces the try block's result and silently discards any exception, hiding real errors.
4. Using finally for Clean-up
Before try-with-resources existed, finally was the standard way to make sure resources were released even when an operation failed:
public class CleanupWithFinally {
static class Connection {
private final String name;
Connection(String name) { this.name = name; System.out.println("open " + name); }
void query(boolean fail) {
if (fail) throw new IllegalStateException("query failed");
System.out.println("query ok on " + name);
}
void close() { System.out.println("close " + name); }
}
static void report(boolean fail) {
Connection c = new Connection("db");
try {
c.query(fail);
} finally {
c.close(); // runs whether query succeeded or failed
}
}
public static void main(String[] args) {
report(false);
try {
report(true);
} catch (IllegalStateException e) {
System.out.println("caller saw: " + e.getMessage());
}
}
}
open db query ok on db close db open db close db caller saw: query failed
The connection was closed in both cases, and the failure still reached the caller, because a try-finally does not catch the exception; it only adds clean-up.
AutoCloseable (files, streams, sockets, JDBC connections), use try-with-resources. It closes resources automatically, in the right order, and handles exceptions thrown while closing. Use finally for other clean-up such as releasing a Lock or restoring a flag.5. When finally Does Not Run
Only a few situations stop a finally block from running:
public class FinallyNotRun {
public static void main(String[] args) {
try {
System.out.println("calling System.exit(0)");
System.exit(0); // the JVM stops immediately
} finally {
System.out.println("this finally block never runs");
}
}
}
calling System.exit(0)
System.exit()orRuntime.halt()is called in the try or catch block.- The JVM crashes or the process is killed (for example with
kill -9). - The thread running the try block never finishes, for example an infinite loop or a deadlock.
- A daemon thread is still inside the try block when the JVM shuts down.
6. Rules
- A try statement can have at most one finally block, and it comes after all catch blocks.
tryneeds at least a catch or a finally (or resources).- Variables declared in the try block are not visible in finally; declare them before the try.
- If finally throws an exception, it replaces any exception from the try or catch block, so guard risky clean-up with its own try-catch.
7. Summary
finallyruns after try (and catch), whether an exception occurred or not.- It runs even after
return,breakandcontinue. - Use it for clean-up; prefer try-with-resources for closeable resources.
- Do not return or throw from finally; it hides results and exceptions.
- It does not run after
System.exit(), a JVM crash, or if the try block never ends.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is the finally block in Java?
A block attached to a try statement that runs after the try (and any catch) completes, whether or not an exception occurred. It is used for clean-up code.
Q2. Does finally always execute?
In almost all cases, yes. It does not run if the JVM exits (System.exit()), crashes or is killed, or if the try block never finishes.
Q3. Does finally run if there is a return in try?
Yes. The return value is evaluated, the finally block runs, and then the method returns that value.
Q4. What happens if finally also has a return statement?
The finally's return replaces the try's return value and discards any pending exception. This is considered very bad practice.
Q5. Can I use try with finally but without catch?
Yes. A try-finally runs clean-up code while letting the exception propagate to the caller.
Q6. Can a try have more than one finally block?
No. Each try statement can have at most one finally block, placed after all catch blocks.
Q7. Does finally run when an exception is not caught?
Yes. The finally block runs first, then the uncaught exception propagates to the caller.
Q8. Does finally run after System.exit()?
No. System.exit() starts shutting down the JVM, and the remaining code in the thread, including finally blocks, does not run. Shutdown hooks do run.
Q9. What happens if an exception occurs inside finally?
It propagates from the finally block and replaces any exception that was already propagating, which is lost. Wrap risky clean-up in its own try-catch.
Q10. What is the difference between finally and try-with-resources?
Try-with-resources automatically closes AutoCloseable resources and keeps closing exceptions as suppressed exceptions. finally is general-purpose clean-up code you write yourself.
Q11. Can I access variables declared in try from finally?
No. Declare them before the try statement, often initialised to null, and check for null in finally.
Q12. Does finally run when break or continue is used?
Yes. If break or continue leaves a try block inside a loop, the finally block runs first.
Q13. Can a finally block change the returned value?
For primitives, changing the variable in finally does not change the already-computed return value. For objects, finally can modify the object that the returned reference points to.
Q14. Is finally related to finalize()?
No. finally is a block of a try statement. finalize() was a deprecated method called by the garbage collector. See final vs finally vs finalize.
Q15. Does finally run in a daemon thread at shutdown?
Not necessarily. When only daemon threads remain, the JVM exits without waiting for them, so their finally blocks may never run.
Q16. Should I close resources in finally?
For AutoCloseable resources, prefer try-with-resources. Use finally for clean-up that does not fit that model, such as unlocking a ReentrantLock.
Q17. Can a finally block contain a try-catch?
Yes, and it is a good idea when clean-up code can itself throw exceptions.
Q18. What is the typical use of finally with locks?
lock.lock();
try {
// critical section
} finally {
lock.unlock(); // always released
}
Q19. Does finally run if the catch block throws an exception?
Yes. The finally block runs, and then the exception from the catch block propagates.
Q20. Is it bad to have a lot of code in finally?
Yes. Keep finally blocks short and focused on clean-up. Complex logic there is hard to reason about and can hide exceptions.