Multiple Catch Blocks and Multi-Catch

Naveen AnamaneniUpdated · 5 min read

One piece of code can fail in more than one way. Reading a quantity from text can fail because the text isn't a number; dividing by it can fail because it's zero. Each problem deserves its own response. A try can have several catch blocks, one per exception type, and Java runs the first one that matches. When several types need the same response, a multi-catch handles them in one block.

One Catch per Problem

PerPerson.java▶ Try it
public class PerPerson {
    static void split(String bill, String people) {
        try {
            int total = Integer.parseInt(bill);
            int n = Integer.parseInt(people);
            System.out.println("Each pays Rs. " + total / n);
        } catch (NumberFormatException e) {
            System.out.println("Please type numbers only: " + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("Can't split among zero people");
        } catch (RuntimeException e) {
            System.out.println("Something else went wrong: " + e);
        }
    }
 
    public static void main(String[] args) {
        split("1200", "4");
        split("1200", "four");
        split("1200", "0");
    }
}
Output
Each pays Rs. 300
Please type numbers only: For input string: "four"
Can't split among zero people

How it works

  1. Java checks the catch blocks from top to bottom and runs the first whose type matches the thrown exception (or is a parent of it).
  2. "four" throws NumberFormatException: the first catch runs, and the others are skipped.
  3. "0" throws ArithmeticException: the first catch doesn't match, the second does.
  4. The last block, RuntimeException, is a safety net for anything else unchecked.

Why Specific Must Come First

If a general type came first, it would catch everything, and the specific block below could never run. Java treats that as a mistake and refuses to compile:

Order.java
public class Order {
    public static void main(String[] args) {
        try {
            Integer.parseInt("x");
        } catch (Exception e) {
            System.out.println("general");
        } catch (NumberFormatException e) {
            System.out.println("specific");
        }
    }
}
Compiler output
Order.java:7: error: exception NumberFormatException has already been caught
        } catch (NumberFormatException e) {
          ^
1 error

Multi-Catch: One Handler for Several Types

When different exceptions need the same handling, list them with | in one catch (Java 7 and later):

MultiCatch.java▶ Try it
public class MultiCatch {
    static int perPerson(String bill, String people) {
        try {
            return Integer.parseInt(bill) / Integer.parseInt(people);
        } catch (NumberFormatException | ArithmeticException e) {
            System.out.println("Bad input (" + e.getClass().getSimpleName()
                + "), using 0");
            return 0;
        }
    }
 
    public static void main(String[] args) {
        System.out.println(perPerson("900", "3"));
        System.out.println(perPerson("900", "x"));
        System.out.println(perPerson("900", "0"));
    }
}
Output
300
Bad input (NumberFormatException), using 0
0
Bad input (ArithmeticException), using 0
0

How it works

catch (NumberFormatException | ArithmeticException e) catches either type. Inside, e really is whichever one was thrown, as getSimpleName() shows.

Two rules apply to multi-catch:

Compiler output: two multi-catch rules
Multi.java:5: error: Alternatives in a multi-catch statement cannot be related by subclassing
        } catch (NumberFormatException | IllegalArgumentException e) {
                                         ^
  Alternative NumberFormatException is a subclass of alternative IllegalArgumentException
MultiFinal.java:6: error: multi-catch parameter e may not be assigned
            e = new ArithmeticException();
            ^
  1. The types can't be parent and child: NumberFormatException already is an IllegalArgumentException, so listing both is pointless.
  2. The variable e is implicitly final; you can't assign a new exception to it.

Common Mistakes

General catch blocks first. It's a compile error; order from specific to general.

Catching Exception as the only block. You lose the chance to respond differently to different problems, and you also catch bugs.

Listing a parent and child in one multi-catch. Keep only the parent, or only the specific types you mean.

Interview Corner

Can we have multiple catch blocks for one try?

Yes. Each catch handles one exception type, and they're checked in order; only the first matching block runs. More specific subclasses must appear before their superclasses, otherwise the compiler reports that the exception "has already been caught".

What is multi-catch?

Since Java 7, a single catch block can handle several unrelated exception types separated by |, as in catch (IOException | SQLException e). The alternatives can't be subclasses of each other, and the catch parameter is implicitly final.

Practice

  1. Easy: Write a method that reads an index and a word from strings and prints the character at that index. Catch NumberFormatException and StringIndexOutOfBoundsException separately.
  2. Harder: Rewrite your answer to use one multi-catch, printing the exception's simple class name.

Quick check: Multiple catch

4 questions
1In which order should catch blocks be written?
2How many catch blocks run for one exception?
3What does catch (A | B e) mean?
4Why can't you write catch (NumberFormatException | IllegalArgumentException e)?

Key Takeaways

Was this tutorial helpful?

Lesson 220 of 482