Exception Hierarchy in Java
Every exception in Java is an object of a class, and those classes form a family tree. Knowing the tree tells you three useful things at a glance: whether the compiler will force you to handle a problem, whether you should try to recover from it, and which catch blocks will catch it. The whole tree grows from one root: Throwable.
The Family Tree
You can ask Java to print each class's ancestors:
public class Ancestors {
static void show(Class<?> c) {
StringBuilder line = new StringBuilder(c.getSimpleName());
Class<?> p = c.getSuperclass();
for (; p != Object.class; p = p.getSuperclass()) {
line.append(" -> ").append(p.getSimpleName());
}
System.out.println(line);
}
public static void main(String[] args) {
show(NumberFormatException.class);
show(NullPointerException.class);
show(java.io.FileNotFoundException.class);
show(StackOverflowError.class);
}
}NumberFormatException -> IllegalArgumentException -> RuntimeException -> Exception -> Throwable
NullPointerException -> RuntimeException -> Exception -> Throwable
FileNotFoundException -> IOException -> Exception -> Throwable
StackOverflowError -> VirtualMachineError -> Error -> ThrowableHow it works
getSuperclass() climbs one level at a time until it reaches Object. Every line ends at Throwable, the only class Java lets you throw and catch.
The Three Branches
| Branch | Means | Examples | Should you catch it? |
|---|---|---|---|
Error | Something is wrong with the JVM or its environment | OutOfMemoryError, StackOverflowError | Almost never; the program usually can't recover |
Exception (excluding RuntimeException) | Expected problems outside your control | IOException, SQLException, InterruptedException | Yes; the compiler requires you to handle or declare them (checked) |
RuntimeException | Usually programming mistakes | NullPointerException, ArithmeticException, IllegalArgumentException | Fix the bug; catch only when you can recover (unchecked) |
The next lesson, "Checked vs Unchecked Exceptions", explains why the compiler treats these branches differently.
Why the Tree Matters for catch
A catch block catches its type and every subclass of it:
catch (...) | Catches |
|---|---|
NumberFormatException | Only NumberFormatException |
IllegalArgumentException | NumberFormatException too, since it's a subclass |
RuntimeException | Every unchecked exception |
Exception | Everything except Errors |
Throwable | Everything, including Errors (avoid this) |
That's why specific catch blocks must come before general ones (see "Multiple Catch Blocks and Multi-Catch").
Common Mistakes
Catching Throwable or Error. You'd also catch OutOfMemoryError, which you can't fix by catching.
Thinking Error and Exception are the same thing. They're siblings with different purposes.
Catching Exception when you only expect one type. You'll also catch bugs you didn't intend to hide.
Interview Corner
Explain the exception hierarchy in Java.
Throwable is the root. It has two subclasses: Error, for serious problems in the JVM or environment such as OutOfMemoryError and StackOverflowError, which applications normally shouldn't catch; and Exception, for conditions a program can handle. RuntimeException is a subclass of Exception for programming errors such as NullPointerException; it and its subclasses, plus Error, are unchecked. All other exceptions, such as IOException, are checked.
What is the difference between Error and Exception?
Both extend Throwable. An Error signals a serious problem in the runtime environment that an application usually can't recover from, like running out of memory. An Exception signals a condition the application might reasonably catch and handle, like a missing file or invalid input.
Practice
- Easy: Use the
showmethod above to print the ancestors ofClassCastException,ArrayIndexOutOfBoundsExceptionandjava.sql.SQLException. - Harder: For each, say which branch it's in and whether the compiler forces you to handle it:
IOException,IllegalStateException,OutOfMemoryError,InterruptedException.
Key Takeaways
Was this tutorial helpful?