Skip to content
Theory · Exceptions · lesson 4 of 12

finally

Back to the building. Whenever someone leaves a floor, calmly after work, because of the alarm or ahead of time, the door closes behind them. It always closes, however the person left.

A program also has code that must run whatever happens: close a file, drop a connection, print a report. Put it at the end of try, and an exception may skip it. Put it after catch, and it gets skipped by an exception that this catch does not catch. For such code try has a third block, finally:

JAVA
public class Main {
    public static void main(String[] args) {
        int[] boxes = {2, 0};
        for (int n : boxes) {
            try {
                System.out.println(8 / n);
            } catch (ArithmeticException e) {
                System.out.println("zero");
            } finally {
                System.out.println("door closed");
            }
        }
    }
}

The program prints:

TEXT
4
door closed
zero
door closed

Three ways out of try

The finally block is written after all the catch blocks. It runs last, however try ended. try has three ways out.

No exception

try runs to the end, catch is skipped, then finally runs. With n equal to 2, the program prints 4, and then door closed.

The exception is caught

try breaks off at the line with the exception, the matching catch runs, and finally after it. With n equal to 0, it prints zero, and then door closed again.

No one catches the exception

There is no matching catch, or no catch at all: try can be written with finally alone. Then finally runs anyway, and after it the exception goes on its way to the calling method.

finally and return

The door also closes when a method leaves early through return:

JAVA
public class Main {
    static int share(int n) {
        try {
            return 10 / n;
        } finally {
            System.out.println("door closed");
        }
    }

    public static void main(String[] args) {
        System.out.println(share(2));
        System.out.println(share(0));
    }
}
TEXT
door closed
5
door closed
Exception in thread "main" java.lang.ArithmeticException: / by zero

Let's go through it step by step:

  1. share(2) computes 10 / 2 for return. But before the method returns 5, finally runs and prints door closed.
  2. main gets 5 and prints it.
  3. share(0): the division throws an exception. There is no catch, but finally still prints door closed.
  4. The exception leaves share for main, no one catches it there either, and the program stops.

This is a classic interview question: does finally run if try has a return? Yes. The value for return is already computed, then finally runs, and only then does the method return the result. finally does not run if the JVM itself stops: for example, if the computer is switched off.

Here the door picture is imprecise. In a building the door closes when you are already out. But finally runs while the method has not finished yet: main is waiting for its 5, and meanwhile share prints door closed.

Common mistake

Code that must always run was placed after try and catch instead of in finally:

JAVA
String s = "0";
try {
    System.out.println(10 / Integer.parseInt(s));
} catch (NumberFormatException e) {
    System.out.println("not a number");
}
System.out.println("door closed"); // ✗
TEXT
Exception in thread "main" java.lang.ArithmeticException: / by zero

The string "0" can be read, but you cannot divide by zero. The catch catches only a NumberFormatException, so the ArithmeticException goes further, and the line after try does not run: the door was left open. Move that line into a finally block after catch. Then door closed is printed here too, before the program stops.

Key points

  • finally runs after try and catch whatever happens: with no exception, with a caught one and with an uncaught one.
  • If try has a return, finally runs before the method returns its value.
  • An uncaught exception passes through finally and goes on to the calling method.
  • Code that must always run goes into finally, not after try.