Menu
Coddy logo textTech

Custom Exceptions

Part of the Object Oriented Programming section of Coddy's Java journey — lesson 60 of 87.

Java's built-in exceptions cover many common error scenarios, but sometimes you need exceptions that are specific to your application's domain. Custom exceptions let you create meaningful error types that clearly communicate what went wrong.

To create a custom exception, simply extend an existing exception class. For a checked exception, extend Exception:

public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

For an unchecked exception, extend RuntimeException:

public class InvalidAgeException extends RuntimeException {
    public InvalidAgeException(String message) {
        super(message);
    }
}

The super(message) call passes the error message to the parent class, making it available through getMessage(). You can then throw and catch your custom exception like any other:

public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException("Balance too low: " + balance);
    }
    balance -= amount;
}

// Using it
try {
    account.withdraw(1000);
} catch (InsufficientFundsException e) {
    System.out.println(e.getMessage());
}

Custom exceptions make your code more readable and allow callers to handle specific error conditions differently. They're especially valuable when building APIs or libraries where clear error communication matters.

challenge icon

Challenge

Easy

Let's build a ticket booking system that uses custom exceptions to handle different error scenarios! You'll create meaningful exception types that clearly communicate what went wrong when booking tickets.

You'll organize your code across four files:

  • TicketSoldOutException.java: Create a custom checked exception (extends Exception) for when tickets are no longer available. Your exception should accept a message in its constructor and pass it to the parent class using super(message).
  • InvalidSeatException.java: Create a custom unchecked exception (extends RuntimeException) for when someone tries to book an invalid seat number. This exception should also accept and pass a message to its parent.
  • TicketBooth.java: Create a class that manages ticket sales. Your booth should track the total number of available seats and the highest valid seat number. Include:

    A constructor that takes the total number of seats available.

    A bookTicket(int seatNumber) method that validates the booking. If no tickets remain (available seats is 0 or less), throw a TicketSoldOutException with the message "No tickets remaining". If the seat number is less than 1 or greater than the total seats, throw an InvalidSeatException with the message "Seat [seatNumber] does not exist". Otherwise, decrease available seats by 1 and print Booked seat [seatNumber] successfully.

    A getAvailableSeats() method that returns the current count of available seats.

  • Main.java: Bring your ticket system together! You'll receive two inputs: the total number of seats and a seat number to book.

    Create a TicketBooth with the given total seats. Then attempt to book the specified seat number inside a try-catch block. Since TicketSoldOutException is checked, you must handle it. Catch TicketSoldOutException first and print Booking failed: [exception message]. Then catch InvalidSeatException and print the same format: Booking failed: [exception message].

    After the try-catch block, print Remaining seats: [count] using the getter method.

You will receive two inputs in order: total seats (integer) and seat number to book (integer).

Notice how checked exceptions force callers to handle them (with try-catch or throws), while unchecked exceptions don't require explicit handling. Choose the exception type based on whether the error is something callers should anticipate and recover from!

Cheat sheet

To create a custom exception, extend an existing exception class.

For a checked exception, extend Exception:

public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

For an unchecked exception, extend RuntimeException:

public class InvalidAgeException extends RuntimeException {
    public InvalidAgeException(String message) {
        super(message);
    }
}

The super(message) call passes the error message to the parent class, making it available through getMessage().

Throw and catch custom exceptions like any other exception:

public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException("Balance too low: " + balance);
    }
    balance -= amount;
}

// Using it
try {
    account.withdraw(1000);
} catch (InsufficientFundsException e) {
    System.out.println(e.getMessage());
}

Checked exceptions force callers to handle them with try-catch or throws. Unchecked exceptions don't require explicit handling. Choose based on whether the error is something callers should anticipate and recover from.

Try it yourself

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int totalSeats = scanner.nextInt();
        int seatNumber = scanner.nextInt();
        
        // TODO: Create a TicketBooth with the given total seats
        
        // TODO: Use a try-catch block to attempt booking the seat
        // - Catch TicketSoldOutException first and print "Booking failed: [exception message]"
        // - Catch InvalidSeatException and print "Booking failed: [exception message]"
        
        // TODO: After the try-catch, print "Remaining seats: [count]"
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming