Skip to content
Theory · Exceptions · lesson 2 of 12

try and catch

In the previous lesson no one answered the alarm, and the program stopped. Now let's put someone on the floor who knows what to do. Java has the try and catch blocks for this:

JAVA
public class Main {
    public static void main(String[] args) {
        int[] boxes = {3, 0, 4};
        for (int n : boxes) {
            try {
                System.out.println(12 / n);
            } catch (ArithmeticException e) {
                System.out.println("Skip: " + e.getMessage());
            }
        }
        System.out.println("Done");
    }
}

The program prints four lines and runs to the end:

TEXT
4
Skip: / by zero
3
Done

The try and catch blocks

What this construct is made of:

  • try { … }: the code where an exception may happen, the floor that is being watched;
  • catch (ArithmeticException e) { … }: what to do if an exception of this class is thrown in try, the person who answers the alarm;
  • e: the variable that holds the exception object itself; e.getMessage() returns its message.

To catch an exception means to run a matching catch instead of stopping the program. Let's go through the run step by step:

  1. n is 3: 12 / 3 prints 4, and catch is skipped.
  2. n is 0: the division throws an ArithmeticException. The rest of try does not run, control passes to catch, and it prints Skip: / by zero.
  3. The loop goes on: with n equal to 4, it prints 3.
  4. After the loop, Done is printed: the program runs to the end.

After catch, the program continues from the line that follows the whole try/catch construct. It never goes back into the interrupted try.

The exception's path through the stack

And what if the exception is thrown deep inside a nested call? Let's take the program with the methods report and average, split the line in report in two and put a try only in main. The rule is:

  1. The method where the exception was thrown ends at once: without return and without its remaining lines.
  2. The exception arrives in the calling method, at the line with the call.
  3. If that line is inside a try with a matching catch, that catch runs.
  4. If not, the calling method ends too, and the search moves on to whoever called it.

This is the alarm sounding floor after floor. Press "Next step" and watch the call frames column. The building is upside down there: the latest call lies on top, like a plate on a pile, and main is at the very bottom. The exception removes the frames one by one until it finds a catch.

LiveAn exception looks for its catchstep 1 of 8 · frames: 1

main enters try and calls report(10, 0).

Frames come off until a try with a matching catch turns up

Notice that the variable avg never got a value, and Done was never printed. Each method on the exception's path stopped at the line where the exception caught up with it.

Interviewers ask it like this: what happens when an exception is thrown? The answer: Java looks for a matching catch, moving from a method to whoever called it, and ends every method on that path. If no catch turns up even in main, the program stops with a stack trace.

Several catch blocks

One try can have several catch blocks, one per exception class:

JAVA
int[] boxes = {3, 0};
for (int i = 0; i <= 2; i++) {
    try {
        System.out.println(12 / boxes[i]); // 4
    } catch (ArithmeticException e) {
        System.out.println("Empty box " + i); // Empty box 1
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("No box " + i); // No box 2
    }
}

Java checks the catch blocks from top to bottom and runs the first one that matches. Only one catch runs:

  • with i equal to 1, the first catch catches the division by zero;
  • with i equal to 2, there is no such cell, and the second one catches the ArrayIndexOutOfBoundsException.

"Matches" means that the exception's class is the class in catch or inherits from it. Exception classes are ordinary classes with parents and subclasses. ArithmeticException, NullPointerException and the other exceptions you know are subclasses of the class Exception, so catch (Exception e) catches any of them.

Here the building picture is imprecise. In a building, anyone who hears the alarm will answer it. But a catch answers only exceptions of its own class and its subclasses, and the rest pass it by and go further.

Hence the rule of order: the catch for the subclass comes first, then the one for the parent. The other way round, the program does not compile; the "Common mistake" section shows it. Interviewers like to ask about the order of catch blocks.

One catch for several classes

If the response to different exceptions is the same, list their classes in one catch, separated by |:

JAVA
String[] inputs = {"6", "x", "0"};
for (String s : inputs) {
    try {
        System.out.println(12 / Integer.parseInt(s));
    } catch (NumberFormatException | ArithmeticException e) {
        System.out.println("Bad input: " + s);
    }
}

The string "x" cannot be read as a number, and parseInt throws a NumberFormatException. The string "0" can be read, but you cannot divide by zero: that is an ArithmeticException. The exceptions differ, but the response is one, so the program prints 2, Bad input: x and Bad input: 0.

You cannot join a parent and its subclass with |: to catch (ArithmeticException | Exception e) the compiler answers Alternatives in a multi-catch statement cannot be related by subclassing. Exception catches both classes anyway.

Common mistake

The catch for the parent was placed above the catch for the subclass:

JAVA
int[] boxes = {3, 0};
try {
    System.out.println(12 / boxes[2]);
} catch (Exception e) {
    System.out.println("Something failed");
} catch (ArrayIndexOutOfBoundsException e) { // ✗
    System.out.println("No such box");
}
TEXT
error: exception ArrayIndexOutOfBoundsException has already been caught

The program does not compile. The first catch catches any Exception, and so an ArrayIndexOutOfBoundsException too. The second catch never gets its turn, and the compiler treats such code as an error. Swap the blocks: first ArrayIndexOutOfBoundsException, then Exception.

Key points

  • If an exception is thrown in try, the rest of try is skipped, the matching catch runs, and then the code after the whole construct.
  • An exception ends every method on its path until it finds a try with a matching catch.
  • Of several catch blocks the first matching one runs, so the catch for a subclass is written before the one for its parent.
  • catch (A | B e) catches exceptions of two classes in one block.