try, catch, and finally

Basic Java
≈ 3 min read

try and catch: attempt and handling

When a section of code can end with an exception, you can place it inside a try block. Immediately after it, you can add one or more catch blocks that describe what to do if an exception of a suitable type occurs.

try {
    int result = 10 / 0;
    System.out.println(result);
} catch (ArithmeticException e) {
    System.out.println("caught");
}

System.out.println("done");

The division causes an ArithmeticException. The remaining part of the try block is no longer executed: control moves to the matching catch. After that block finishes, the program continues with the statement after the whole construct. That is why the example prints caught first and then done.

The variable e contains the exception object that occurred. You can work with it like with any other object of the corresponding type.

catch runs only for a matching type

The type in parentheses determines which exceptions a particular catch can handle. The inheritance rules you already know apply here: a handler matches not only the specified class, but also its subclasses.

try {
    String[] values = {"10", "20"};
    int index = Integer.parseInt("5");
    System.out.println(values[index]);
} catch (NumberFormatException e) {
    System.out.println("bad number");
} catch (IndexOutOfBoundsException e) {
    System.out.println("bad index");
}

The string "5" is converted to a number successfully, so the first catch is not needed. The program then accesses an array element that does not exist, an IndexOutOfBoundsException occurs, and control moves to the second handler.

When there are several handlers, Java checks them from top to bottom and uses the first matching one. That is why a more general type cannot be placed before one of its more specific subclasses: otherwise the lower handler could never run.

try {
    int value = Integer.parseInt("abc");
} catch (Exception e) {
    System.out.println("exception");
} catch (NumberFormatException e) {
    System.out.println("number");
}
This code does not compile. NumberFormatException is a subclass of Exception, so the first catch already catches all such exceptions. More specific handlers are placed before more general ones.

If there is no exception, catch is skipped

A catch block is not part of the normal execution path. If the entire try block finishes without an exception, the handlers are simply skipped and the program continues.

try {
    int result = 10 / 2;
    System.out.println(result);
} catch (ArithmeticException e) {
    System.out.println("caught");
}

System.out.println("done");

There is no exception here, so the program prints 5 and then done.

finally runs after try and catch

After try and any catch blocks, you can add a finally block. It is intended for code that should run after this attempt regardless of whether an exception occurred.

try {
    System.out.println("try");
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("catch");
} finally {
    System.out.println("finally");
}

System.out.println("done");

This code prints try, then catch, then finally, and only after that done. If no exception occurs in the try block, the catch block is skipped, but finally still runs.

This way, the construct separates three roles: try contains code where an exceptional situation may occur, catch reacts to a matching exception, and finally performs an action after that attempt finishes.