Question
Does a finally Block Always Execute in Java? Exceptions, Return, and Edge Cases
Question
In Java, can you be completely certain that a finally block will always execute, regardless of what something() does?
For example:
try {
something();
return success;
} catch (Exception e) {
return failure;
} finally {
System.out.println("I don't know if this will get printed out");
}
I want to know whether the finally block is guaranteed to run in all cases, including when the try block returns a value or when an exception occurs.
Short Answer
By the end of this page, you will understand what Java's finally block is for, when it normally executes, how it behaves with return statements and exceptions, and the important edge cases where it may not run. You will also see how finally compares with modern alternatives like try-with-resources.
Concept
In Java, a finally block is used to run cleanup code after a try/catch block. Its main purpose is to ensure that important cleanup work happens whether the main code succeeds or fails.
Typical cleanup tasks include:
- Closing files
- Releasing database connections
- Unlocking locks
- Cleaning temporary state
Normal behavior
In normal Java execution, a finally block runs:
- after the
tryblock finishes - after a
catchblock finishes - even if the
tryorcatchblock containsreturn - even if an exception is thrown and caught
So for code like this:
try {
return 1;
} finally {
System.out.println("Runs before method actually returns");
}
the finally block runs before the method returns 1.
Why this matters
Without finally, cleanup code could be skipped whenever an error happens or when a method exits early. That can lead to resource leaks, locked files, open connections, or inconsistent state.
Important edge cases
Although finally is usually executed, it is not an absolute guarantee in every possible situation. It may not run if:
- the JVM shuts down abruptly, such as with
System.exit() - the process is forcibly killed
- the machine loses power
- the JVM crashes due to a fatal error
- the thread never gets a chance to continue execution
So the practical rule is:
- During normal program flow, yes,
finallyruns. - In abnormal JVM termination scenarios, no language feature can guarantee execution.
In your example
For this code:
try {
something();
return success;
} catch (Exception e) {
return failure;
} finally {
System.out.println("I don't know if this will get printed out");
}
System.out.println(...) will run in normal execution whether:
something()completes successfullysomething()throws anExceptioncaught by thecatch- the
tryblock reachesreturn success - the
catchblock reachesreturn failure
But if something() terminates the JVM or the program is forcibly stopped, the finally block may not execute.
Mental Model
Think of try, catch, and finally like leaving a room:
tryis the main task you came to do.catchis what you do if something goes wrong.finallyis turning off the lights and locking the door before leaving.
Even if you finish your task early and head for the exit with return, Java still says, "Wait—do the cleanup first."
But if the whole building suddenly disappears—like a power failure or forced shutdown—there may be no chance to lock the door. That is why finally is reliable in normal execution, but not magical in catastrophic situations.
Syntax and Examples
Basic syntax
try {
// code that may fail
} catch (Exception e) {
// handle the exception
} finally {
// cleanup code
}
Example 1: finally runs after success
public static int demo() {
try {
System.out.println("In try");
return 10;
} finally {
System.out.println("In finally");
}
}
Output:
In try
In finally
The method still returns 10, but only after the finally block runs.
Example 2: finally runs after a caught exception
public static String demo() {
try {
throw new RuntimeException("Boom");
} catch (RuntimeException e) {
System.out.println("In catch");
return "failed";
} finally {
System.out.println("In finally");
}
}
Output:
In catch
In finally
Again, finally runs before the method returns.
Example 3: finally can override a return value
public static int demo() {
try {
return 1;
} finally {
return 2;
}
}
This returns 2.
That is legal Java, but it is strongly discouraged because it hides what happened in the try block and can also suppress exceptions.
Example 4: finally may not run if the JVM exits
public static void demo() {
try {
System.out.println("In try");
System.exit(0);
} finally {
System.out.println("This will likely not print");
}
}
Here, the JVM exits before normal control flow can continue, so finally does not get a chance to run.
Step by Step Execution
Consider this method:
public static String check() {
try {
System.out.println("Step 1: try starts");
return "success";
} catch (Exception e) {
System.out.println("Step 2: catch runs");
return "failure";
} finally {
System.out.println("Step 3: finally runs");
}
}
What happens step by step
- The
tryblock starts. System.out.println("Step 1: try starts")runs.- Java sees
return "success";. - Before the method actually returns, Java executes the
finallyblock. System.out.println("Step 3: finally runs")runs.- The method returns
"success".
Output:
Step 1: try starts
Step 3: finally runs
Returned value:
success
If an exception happens instead
public static String check() {
try {
System.out.println("Step 1: try starts");
throw new Exception();
} catch (Exception e) {
System.out.println("Step 2: catch runs");
return "failure";
} finally {
System.out.println("Step 3: finally runs");
}
}
Execution order:
trystarts.- An exception is thrown.
catchhandles the exception.- Java sees
return "failure";. - Before returning, Java runs
finally. - The method returns
"failure".
Output:
Step 1: try starts
Step 2: catch runs
Step 3: finally runs
Real World Use Cases
finally is mainly used for cleanup that must happen after work is attempted.
Common examples
Closing a file or stream
InputStream in = null;
try {
in = new FileInputStream("data.txt");
// read file
} catch (IOException e) {
// handle error
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// handle close error
}
}
}
Releasing a lock
lock.lock();
try {
// critical section
} finally {
lock.unlock();
}
This is a very common and important use of finally.
Cleaning up temporary state
boolean previous = loggingEnabled;
loggingEnabled = false;
try {
// do work with logging disabled
} finally {
loggingEnabled = previous;
}
Database or network cleanup
Older Java code often uses finally to close:
- JDBC connections
- statements
- result sets
- sockets
In newer Java, try-with-resources is often preferred for these cases.
Real Codebase Usage
In real projects, developers use finally for cleanup that must happen no matter how the earlier code exits.
Common patterns
Guarded resource cleanup
Older codebases often use null checks inside finally:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("input.txt"));
return reader.readLine();
} finally {
if (reader != null) {
reader.close();
}
}
Lock handling
This is still very common in modern code:
lock.lock();
try {
processSharedData();
} finally {
lock.unlock();
}
Timing or metrics collection
long start = System.currentTimeMillis();
try {
runTask();
} finally {
long duration = System.currentTimeMillis() - start;
System.out.println("Task took " + duration + "ms");
}
Resetting state
setProcessing(true);
try {
doWork();
} finally {
setProcessing(false);
}
Modern preference: try-with-resources
For Closeable or AutoCloseable resources, Java developers usually prefer try-with-resources because it is clearer and safer:
try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) {
return reader.readLine();
}
This reduces boilerplate and avoids many manual cleanup mistakes.
Common Mistakes
1. Assuming finally means literally always
Beginners often hear that finally "always runs" and take that as an absolute rule.
That is not fully correct.
Problem cases
System.exit()- forced process termination
- JVM crash
- machine shutdown
2. Returning from finally
This is one of the most dangerous mistakes.
Broken example
public static int test() {
try {
return 1;
} finally {
return 2;
}
}
This returns 2, not 1.
It can also hide exceptions:
public static int test() {
try {
throw new RuntimeException("boom");
} finally {
return 2;
}
}
The exception is suppressed, and the method returns 2.
Avoid it
Do not return from finally unless you have an extremely unusual reason.
3. Throwing new exceptions from finally carelessly
try {
throw new RuntimeException("original");
} finally {
throw new RuntimeException("new one");
}
The new exception replaces the original one.
That makes debugging harder.
4. Using finally for resource handling when try-with-resources is better
Manual cleanup is easy to get wrong:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
} finally {
if (reader != null) {
reader.close();
}
}
Prefer:
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
// use reader
}
5. Catching overly broad exceptions without good reason
catch (Exception e) {
return failure;
}
This may hide useful information or swallow exceptions you did not intend to handle.
Catch the most specific exception type you can.
6. Putting essential business logic in finally
finally should usually be for cleanup, not core application decisions. Keep it focused on cleanup or guaranteed post-processing.
Comparisons
| Concept | Purpose | Runs on success? | Runs on exception? | Best use |
|---|---|---|---|---|
try | Main code to attempt | Yes | Starts here | Code that may fail |
catch | Handle exceptions | No | Yes, if matched | Error handling |
finally | Cleanup or guaranteed follow-up | Yes | Yes, usually | Releasing resources, unlocking |
| try-with-resources | Automatic resource cleanup | Yes | Yes | Files, streams, DB resources |
finally vs try-with-resources
| Feature | finally | try-with-resources |
|---|---|---|
| Manual cleanup | Yes | No |
| Good for locks/state reset | Yes | Usually not |
| Good for streams/files | Possible | Preferred |
| Boilerplate | More | Less |
Safer for AutoCloseable resources | Less | More |
catch vs finally
- Use
catchwhen you want to handle an error. - Use
finallywhen you want to run cleanup code regardless of outcome.
return inside try vs return inside finally
| Location | Effect |
|---|---|
return in try | Schedules a return, then finally runs |
return in catch | Schedules a return, then finally runs |
return in finally | Overrides earlier return values and may suppress exceptions |
Cheat Sheet
Quick rules
finallyusually runs aftertryandcatch.finallystill runs iftryorcatchcontainsreturn.finallyis mainly for cleanup.finallydoes not guarantee execution if the JVM stops abruptly.- Avoid
returninsidefinally. - Prefer try-with-resources for files, streams, and other
AutoCloseableresources.
Core syntax
try {
// risky code
} catch (Exception e) {
// handle error
} finally {
// cleanup
}
Common behavior
try {
return 1;
} finally {
System.out.println("runs first");
}
- prints
runs first - then returns
1
Dangerous pattern
try {
return 1;
} finally {
return 2;
}
- returns
2 - hides the earlier return
Cases where finally may not run
System.exit(...)- JVM crash
- forced kill by OS or container
- power failure
Best uses
lock.unlock()- resetting flags
- metrics/timing cleanup
- legacy resource cleanup
Prefer this for closeable resources
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
return reader.readLine();
}
FAQ
Does finally always run after a return in Java?
Yes, in normal execution. Java runs the finally block before the method actually returns.
Can a finally block fail to execute?
Yes. It may not run if the JVM exits abruptly, the process is killed, or the machine crashes.
Does finally run if an exception is thrown?
Yes, if execution continues normally through Java's exception handling. It runs whether the exception is caught or propagates upward, unless the JVM stops abruptly.
Can finally change the return value?
Yes. If you return from finally, it overrides earlier returns. This is usually a bad idea.
Is finally still useful in modern Java?
Yes, especially for unlocking, resetting state, or guaranteed follow-up actions. But for closing files and streams, try-with-resources is usually better.
What is better than finally for closing files in Java?
Try-with-resources is usually the best choice for files, streams, sockets, and other AutoCloseable objects.
Does finally run if the catch block returns?
Yes. A return in catch still causes finally to run before the method exits.
Mini Project
Description
Build a small Java program that demonstrates how finally behaves in three common situations: normal success, caught exception, and JVM shutdown. This project helps you see that finally usually runs, but not in every possible case.
Goal
Create a program that prints and compares the behavior of finally during normal control flow, exception handling, and abrupt JVM exit.
Requirements
- Write one method where the
tryblock returns successfully andfinallyprints a message. - Write one method where the
tryblock throws an exception, thecatchblock returns a value, andfinallyprints a message. - Write one method that calls
System.exit(0)insidetry. - Call the methods from
mainand observe which messages are printed. - Keep the code in plain Java without external libraries.
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.