75. The Exception Hierarchy
Throwable is the root; Error represents unrecoverable JVM failures (don't catch); Exception is the recoverable root; RuntimeException is the unchecked subclass. Know where to catch and what to rethrow.
Explanation
`` Throwable Error <- JVM errors: OutOfMemoryError, StackOverflowError, AssertionError Exception <- root of checked exceptions RuntimeException <- unchecked: NullPointerException, IllegalArgumentException, etc. IOException <- checked: FileNotFoundException, SocketException, etc. SQLException <- checked: database errors ... ``
Never catch Error: OutOfMemoryError, StackOverflowError, InternalError signal the JVM is in an unrecoverable state. Catching them and continuing leads to undefined behaviour.
Catch as specific as possible: catch FileNotFoundException before IOException before Exception. A catch block catches the declared type and all subtypes. Ordering matters โ the first matching catch wins.
Multi-catch (catch (A | B e)): catch two unrelated exceptions in one block. The caught type is the common supertype; the variable is implicitly final.
finally always runs: even if return is called inside try or catch. try-with-resources replaced most explicit finally cleanup patterns.
Example
import java.io.*;
import java.sql.SQLException;
public class ExceptionHierarchy {
public static void main(String[] args) {
// Specific before general
try {
throw new FileNotFoundException("/missing.txt");
} catch (FileNotFoundException e) {
System.out.println("FileNotFound: " + e.getMessage());
} catch (IOException e) {
System.out.println("IO: " + e.getMessage()); // never reached here
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
// Multi-catch: unrelated exception types in one block
try {
if (Math.random() < 0.5) throw new IOException("io");
else throw new SQLException("sql");
} catch (IOException | SQLException e) {
// e is implicitly final; type is common supertype (Exception)
System.out.println("IO or SQL: " + e.getMessage());
}
// finally always runs
try {
System.out.println("try block");
if (true) return; // still runs finally!
} finally {
System.out.println("finally runs even with return");
}
}
static void demonstrateErrors() {
// NEVER catch Error in production code
try {
int[] huge = new int[Integer.MAX_VALUE]; // OutOfMemoryError
} catch (OutOfMemoryError e) {
// Bad practice: JVM may be in broken state
System.out.println("OOM caught โ heap may be exhausted");
}
}
}Sources
- https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html โ Exceptions tutorial
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Throwable.html โ Throwable API