Multi-catch in Java
catch (A | B e) and the rule about related types.
One handler, many types
A multi-catch handles several exception types in one block, separated by **|**. Whichever of them is thrown, the same handler runs — no duplicated code.
try {
loadUser(id);
} catch (IOException | SQLException e) {
log.error("load failed", e);
}One net, two fish
What does this print?
Object[] items = {"7", 3, "z"};
for (Object o : items) {
try {
String s = (String) o;
System.out.print(Integer.parseInt(s));
} catch (ClassCastException
| NumberFormatException e) {
System.out.print("-");
}
}7--7-7Throws ClassCastException
Show the answer
"7" parses fine. 3 can't be cast to String (ClassCastException), and "z" can't be parsed (NumberFormatException). One handler covers both, and the loop keeps going.
What is e?
In a multi-catch, e has the type of the alternatives' closest common supertype. For FileNotFoundException | SQLException that's Exception, so you can call getMessage() without a cast. And e is implicitly final — assigning to it is a compile error.
catch (FileNotFoundException
| SQLException e) {
e.getMessage(); // Exception methods
e = null; // compile error
}No relatives allowed
The alternatives must not be subclasses of each other. NumberFormatException already is an IllegalArgumentException, so listing both is redundant — and a compile error.
try {
Integer.parseInt("7");
} catch (NumberFormatException
| IllegalArgumentException e) { // error
}Merging handlers
try {
process();
} catch (Exception e) {
log(e);
}Also swallows unrelated bugs like NullPointerException.
try {
process();
} catch (IOException | SQLException e) {
log(e);
}Removes the duplication without widening the net.
Taming noisy APIs
Reflection is the classic case: Class.forName(...).getMethod(...).invoke(...) can throw several checked exceptions. Multi-catch keeps that handling to one block. Java 7 also added ReflectiveOperationException as their common parent for when you want them all.
Key takeaways
- catch (A | B e) — one handler for several types
- Alternatives can't be related by subclassing
- e is implicitly final; you can't reassign it
- e's type is the closest common supertype of the alternatives
Multi-catch arrived in Java 7 (2011) with Project Coin — alongside try-with-resources, the diamond <> and strings in switch.
Practice questions
What does this print?
int[] d = {5, 0};
for (int i = 0; i < 3; i++) {
try {
System.out.print(10 / d[i]);
} catch (ArithmeticException
| ArrayIndexOutOfBoundsException e) {
System.out.print("!");
}
}- 2!!
- 2!
- 2
- Throws ArrayIndexOutOfBoundsException
Check your answer
2!!. 10 / 5 prints 2; 10 / 0 throws ArithmeticException; d[2] throws ArrayIndexOutOfBoundsException. One handler covers both.
What does this print?
try {
Integer.parseInt("7");
} catch (NumberFormatException | IllegalArgumentException e) {
System.out.println("bad");
}
System.out.println("ok");- ok
- bad ok
- Compile error
Check your answer
Compile error. NumberFormatException is a subclass of IllegalArgumentException, so listing both is redundant and rejected.