Finally Block in Java

Naveen AnamaneniUpdated · 5 min read

Some work must happen no matter what: closing a file you opened, releasing a lock, printing "done" in a log. If that cleanup sits after the try-catch, an unexpected exception or an early return can skip it. A finally block runs after the try (and any catch) in every normal case: when the try succeeds, when an exception is caught, when it isn't caught, and even when the try returns.

It Runs on Every Path

finally runs on success, on a caught exception, on an uncaught one, and before a return
Always.java▶ Try it
public class Always {
    static void attempt(String input) {
        try {
            System.out.println("try: " + Integer.parseInt(input));
        } catch (NumberFormatException e) {
            System.out.println("catch: bad input");
        } finally {
            System.out.println("finally: always runs");
        }
    }
 
    static int value() {
        try {
            return 1;
        } finally {
            System.out.println("finally: runs before the return");
        }
    }
 
    public static void main(String[] args) {
        attempt("42");
        attempt("x");
        System.out.println("value = " + value());
    }
}
Output
try: 42
finally: always runs
catch: bad input
finally: always runs
finally: runs before the return
value = 1

How it works

  1. With "42", try succeeds, catch is skipped, then finally runs.
  2. With "x", the exception is caught, then finally runs.
  3. In value(), return 1 is about to leave the method, but Java runs finally first, then completes the return.

What finally Is For

Cleanup that must not be skipped:

ResourceCleanup in finally
A locklock.unlock()
A file or connection (old style)reader.close()
A temporary settingRestore the old value
Timing or loggingRecord "finished"

For files, streams and connections, try-with-resources is now better than finally (see "Try-With-Resources in Java"): it closes things automatically and handles errors during closing.

When finally Does Not Run

finally runs on every normal path, but not when the JVM itself stops:

SituationDoes finally run?
System.exit(...) called in try or catchNo: the JVM shuts down immediately
The JVM crashes, or the process is killed (power cut, kill -9)No
An infinite loop or a deadlock inside tryNo: try never finishes
The thread running it is a daemon thread and the program endsNot guaranteed
Exit.java▶ Try it
public class Exit {
    public static void main(String[] args) {
        try {
            System.out.println("about to exit");
            System.exit(0);
        } finally {
            System.out.println("this never prints");
        }
    }
}
Output
about to exit

Two Traps with return

Traps.java▶ Try it
public class Traps {
    @SuppressWarnings("finally")
    static int overrides() {
        try {
            return 1;
        } finally {
            return 2;
        }
    }
 
    static int unchanged() {
        int x = 10;
        try {
            return x;
        } finally {
            x = 20;
        }
    }
 
    public static void main(String[] args) {
        System.out.println(overrides());
        System.out.println(unchanged());
    }
}
Output
2
10

How it works

  1. A return inside finally replaces the try's return value, and it would also swallow any exception the try threw. The compiler warns about it with -Xlint (silenced here with @SuppressWarnings to show the effect).
  2. In unchanged(), the value 10 is saved when return x runs. Changing x in finally doesn't change what's returned.

Under the Hood

The JVM has no "finally" instruction. The compiler copies the finally code onto every way out of the try, and uses the method's exception table to route exceptions:

javap -c (trimmed): try, catch and finally in one method
         5: getstatic     #13   // System.out
         8: ldc           #19   // String done        <- finally copy 1 (after try)
        ...
        18: getstatic     #13   // System.out
        21: ldc           #19   // String done        <- finally copy 2 (after catch)
        ...
        29: getstatic     #13   // System.out
        32: ldc           #19   // String done        <- finally copy 3 (any other exception)
        38: athrow
      Exception table:
         from    to  target type
             0     5    15   Class java/lang/NumberFormatException
             0     5    28   any
            15    18    28   any

The any rows send any other exception to the third copy, which runs the cleanup and then rethrows with athrow.

Interview Corner

Does finally always execute?

It executes after try and catch on every normal path: normal completion, a caught or uncaught exception, and return, break or continue inside try. It doesn't run if the JVM stops first, for example via System.exit, a crash or the process being killed, or if the try never completes, as in an infinite loop.

What happens if both try and finally have a return statement?

The return in finally wins: its value is returned, and any value or exception from the try block is discarded. That's why returning from finally is considered bad practice.

Practice

  1. Easy: Write a method that prints "Start", then divides two numbers inside try, catches ArithmeticException, and prints "End" in finally. Call it with a zero and a non-zero divisor.
  2. Harder: Inside a for loop, put a try with continue for odd numbers and a finally that prints the number. Predict the output, then run it.

Quick check: finally

4 questions
1When does finally run?
2Does finally run after System.exit(0) in try?
3try returns 1 and finally returns 2. What does the method return?
4What's the modern alternative to closing files in finally?

Key Takeaways

Was this tutorial helpful?

Lesson 222 of 482