Multi-catch and Custom Exceptions
Multi-catch
A single catch block can handle multiple exception types with |:
javatry {
process();
} catch (IOException | SQLException e) {
log("Data error: " + e.getMessage());
}- The variable
eis implicitly final inside a multi-catch block — it cannot be reassigned. - The types must not be in an inheritance relationship (would be a compile error):
javacatch (IOException | FileNotFoundException e) { } // COMPILE ERROR — FileNotFoundException extends IOExceptionRethrowing with Precise Type Inference
When a caught exception is rethrown and the compiler can determine its precise type, the throws declaration can be more specific:
javavoid process() throws IOException, SQLException {
try {
riskyOperation();
} catch (Exception e) {
log(e);
throw e; // compiler infers IOException | SQLException, not Exception
}
}Custom Checked Exception
Extend Exception (or a checked subclass):
javapublic class InsufficientFundsException extends Exception {
private final double amount;
public InsufficientFundsException(double amount) {
super("Insufficient funds: need " + amount + " more");
this.amount = amount;
}
public double getAmount() { return amount; }
}Usage:
javavoid withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) throw new InsufficientFundsException(amount - balance);
balance -= amount;
}Custom Unchecked Exception
Extend RuntimeException:
javapublic class ConfigurationException extends RuntimeException {
public ConfigurationException(String message) {
super(message);
}
public ConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}The two-argument form preserves the original cause (useful for wrapping lower-level exceptions).
Exception Chaining
Wrapping one exception inside another preserves the root cause:
javatry {
Files.readString(path);
} catch (IOException e) {
throw new ConfigurationException("Cannot read config file", e); // e is the cause
}javacatch (ConfigurationException e) {
System.out.println("Cause: " + e.getCause());
}Best Practices
| Practice | Reason |
|---|---|
| Catch specific types first | Avoid swallowing unexpected exceptions |
| Include the cause when wrapping | Preserves the full root-cause chain |
| Use checked exceptions for recoverable conditions | Forces callers to handle them |
| Use unchecked for programming errors | IllegalArgumentException, IllegalStateException |
Never catch Throwable/Error in normal code |
JVM errors should propagate |
Common Standard Exceptions to Know
| Exception | Type | Thrown when |
|---|---|---|
NullPointerException |
Unchecked | Dereferencing null |
ArrayIndexOutOfBoundsException |
Unchecked | Array index out of range |
ClassCastException |
Unchecked | Invalid downcast |
ArithmeticException |
Unchecked | Division by zero (integers) |
IllegalArgumentException |
Unchecked | Invalid method argument |
IllegalStateException |
Unchecked | Object in wrong state |
UnsupportedOperationException |
Unchecked | Operation not supported |
IOException |
Checked | I/O failure |
FileNotFoundException |
Checked | File does not exist |
NumberFormatException |
Unchecked | Integer.parseInt("abc") |
StackOverflowError |
Error | Infinite recursion |