Skip to Content
Course content

57: Creating Custom Exceptions

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're at a high-end restaurant. You order the signature sea bass, but a few minutes later, the waiter comes back and says, "There was an error with your order." That's frustrating, right? It's technically true, but it's useless. You don't know if the kitchen is on fire, if they're out of fish, or if the waiter just forgot to write it down. Now, imagine the waiter says, "I'm sorry, we've just sold the last portion of the sea bass." That's a specific, actionable piece of information. You can now make a decision: order the salmon or go to a different restaurant.

In Java, using generic exceptions like RuntimeException or IllegalArgumentException is like the waiter saying "there was an error." It tells the program something went wrong, but it doesn't tell the calling code why it happened in a way that allows for a specific recovery strategy. That's where custom exceptions come in.

When generic exceptions fail us

I've spent years maintaining legacy codebases where every single error was just thrown as a generic Exception. It's a nightmare. When you're catching an error, you want to be able to distinguish between a "the database is down" error (which requires a retry) and a "the user entered a negative age" error (which requires a validation message). If both are just generic exceptions, you end up parsing string messages to figure out what happened—which is a fragile, terrible way to write software.

Let's look at a movie ticket booking system. If a user tries to book a seat that's already taken, throwing an IllegalStateException might work, but it's vague. We want a SeatAlreadyTakenException.

Building your own exception blueprint

Creating a custom exception is surprisingly simple because you're just leveraging inheritance. You create a class that extends either Exception (for checked exceptions) or RuntimeException (for unchecked exceptions).

public class SeatAlreadyTakenException extends Exception {
    private final int seatNumber;

    public SeatAlreadyTakenException(String message, int seatNumber) {
        super(message); 
        this.seatNumber = seatNumber;
    }

    public int getSeatNumber() {
        return seatNumber;
    }
}

Notice what's happening here. I'm calling super(message). This passes the error message up to the parent Exception class so that when you call printStackTrace() or getMessage(), Java knows what to display. I also added a seatNumber field. This is the "secret sauce" of custom exceptions: you can attach extra data to the exception that the catching block can use to fix the problem.

Throwing and catching with precision

Now that we have our specific "out of fish" signal, we can use it in our business logic. When we throw this exception, we are explicitly telling anyone who calls this method: "Hey, this specific thing might happen, so be prepared to handle it."

public void bookSeat(int seatNumber) throws SeatAlreadyTakenException {
    if (inventory.isOccupied(seatNumber)) {
        throw new SeatAlreadyTakenException("Seat " + seatNumber + " is already booked!", seatNumber);
    }
    inventory.markAsTaken(seatNumber);
}

// Elsewhere in the code...
try {
    bookingService.bookSeat(42);
} catch (SeatAlreadyTakenException e) {
    System.out.println("Sorry! Seat " + e.getSeatNumber() + " is gone. Try seat 43?");
}

The Checked vs. Unchecked dilemma

You'll notice I extended Exception, which makes this a checked exception. This forces the developer to either wrap the call in a try-catch block or declare that their method also throws it. I usually recommend checked exceptions for "recoverable" errors—things the user can actually fix. If the error is a result of a programming bug (like a null pointer), extend RuntimeException instead. Don't force your teammates to catch exceptions that they can't possibly recover from; that just leads to empty catch blocks, which is a cardinal sin in professional Java development.




📋 Practical Task

Implementing a CriticalTemperatureException for a Greenhouse Controller

You are building a monitoring system for a smart greenhouse. If the temperature exceeds 40 degrees Celsius, the system must throw a custom exception that not only signals the error but also carries the actual temperature reading so the cooling system knows how hard to work.

Your Task:

  • Create a custom exception class named CriticalTemperatureException that extends Exception.
  • Add a private field double temperature to the exception class.
  • Create a constructor that accepts a String message and the double temperature.
  • Create a method getTemperature() to retrieve the value.
  • Write a class GreenhouseMonitor with a method checkTemperature(double currentTemp). If currentTemp is greater than 40.0, throw your custom exception.
  • In a main method, call checkTemperature(45.5) inside a try-catch block and print a message that includes the temperature retrieved from the exception object.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.