Memra

Custom exceptions & common built-ins

Writing your own exception types, chaining causes, and picking the right built-in.

Writing your own exception types

Custom exceptions let you communicate domain-specific errors in the type system. The choice of base class determines checkedness:

// Checked — callers MUST handle or declare
public class InsufficientFundsException extends Exception {
    private final double amount;

    public InsufficientFundsException(double amount) {
        super("Insufficient funds: need " + amount + " more");
        this.amount = amount;
    }

    // Constructor that chains a cause
    public InsufficientFundsException(double amount, Throwable cause) {
        super("Insufficient funds: need " + amount + " more", cause);
        this.amount = amount;
    }

    public double getAmount() { return amount; }
}

// Unchecked — extend RuntimeException
public class ConfigurationException extends RuntimeException {
    public ConfigurationException(String msg) { super(msg); }
    public ConfigurationException(String msg, Throwable cause) { super(msg, cause); }
}

When to make an exception checked vs unchecked:

- Checked: the caller can reasonably recover — InsufficientFundsException makes sense to catch and prompt the user. - Unchecked: the caller cannot reasonably recover, or the exception indicates a programming error — ConfigurationException at startup is usually fatal.

Modern Java (and most frameworks) lean toward unchecked exceptions for application logic; checked exceptions for I/O and transactional operations where retry/fallback is expected.

Common built-in exceptions to know for OCP:

| Exception | Unchecked? | Cause | |---|---|---| | NullPointerException | yes | null dereference | | IllegalArgumentException | yes | invalid method argument | | IllegalStateException | yes | object in wrong state | | ClassCastException | yes | invalid downcast | | NumberFormatException | yes | bad numeric string | | StackOverflowError | yes (Error) | infinite recursion | | ArithmeticException | yes | e.g. integer divide by zero | | IOException | checked | I/O failure | | FileNotFoundException | checked | file not found (extends IOException) |

Always provide at minimum two constructors: one taking a String message, and one taking both a String and a Throwable cause — so callers can wrap underlying exceptions without losing the chain.

NORMAL ~/memra/learn/java-from-zero/custom-exceptions utf-8 LF