Custom Exceptions

Creating Your Own

Create a custom exception when a business rule fails: InsufficientBalanceException, ProductOutOfStockException. Extend RuntimeException (unchecked, most common today) or Exception (checked).

Example

public class Main {
    public static void main(String[] args) {
        Inventory inv = new Inventory();
        try {
            inv.reserve("iPhone 15", 2);
            inv.reserve("iPhone 15", 5);
        } catch (OutOfStockException e) {
            System.out.println("Error: " + e.getMessage());
            System.out.println("Product: " + e.getProduct() + ", available: " + e.getAvailable());
        }
    }
}

class OutOfStockException extends RuntimeException {
    private final String product;
    private final int available;

    OutOfStockException(String product, int requested, int available) {
        super("Requested " + requested + " of " + product + " but only " + available + " left");
        this.product = product;
        this.available = available;
    }

    String getProduct() { return product; }
    int getAvailable() { return available; }
}

class Inventory {
    private int stock = 4;

    void reserve(String product, int qty) {
        if (qty > stock) {
            throw new OutOfStockException(product, qty, stock);
        }
        stock -= qty;
        System.out.println("Reserved " + qty + ", stock now " + stock);
    }
}

Output

Reserved 2, stock now 2
Error: Requested 5 of iPhone 15 but only 2 left
Product: iPhone 15, available: 2

Uncaught Custom Exception

Example

If nobody catches it, the program stops with your exception and message.

public class Main {
    public static void main(String[] args) {
        withdraw(500, 1200);
    }

    static void withdraw(int balance, int amount) {
        if (amount > balance) {
            throw new InsufficientBalanceException("Balance " + balance + " is less than " + amount);
        }
    }
}

class InsufficientBalanceException extends RuntimeException {
    InsufficientBalanceException(String message) {
        super(message);
    }
}

Output

Exception: InsufficientBalanceException: Balance 500 is less than 1200

Best Practices

  • Never swallow exceptions with an empty catch {}. At least log them.
  • Catch the most specific type you can handle; do not catch Exception everywhere.
  • Give clear messages with the values involved ("Order 42 not found").
  • Keep the cause when wrapping: new AppException("msg", e).
  • Do not use exceptions for normal flow control (like ending a loop).