Exercise 2.8: Creating Custom Exceptions

Author

Chuck Nelson

Published

October 23, 2025

1 Purpose

In the last exercise, you learned to handle different built-in Java exceptions. Now, it’s time to learn how to create your own. While Java provides many standard exceptions, sometimes you need to represent an error that is specific to your application’s logic. Custom exceptions make your code more readable and self-documenting by giving a precise name to a specific problem.

2 What You’ll Accomplish

By the end of this exercise, you will have:

  • Defined your own custom exception class.
  • Modified a method to throw your custom exception.
  • Written a catch block to specifically handle your custom exception.
  • Understood the value of creating domain-specific exceptions for your application.
  • 4. Problem-Solving and Critical Thinking:
    • 4.1 Decompose complex problems into smaller, manageable components.
    • 4.3 Identify, analyze, and debug software errors.
  • 5. Software Development Lifecycle:
    • 5.2 Implement software solutions using a programming language.
  • Learning Objectives:
    • Define a class that inherits from java.lang.Exception.
    • Instantiate and throw a custom exception for a business rule violation.
    • Implement a try-catch block to handle the custom exception.
  • **Knowledge, Skills, and Abilities (KSAs) from O*NET:**
    • 15-1251.00 - Computer Programmers:
      • Knowledge of computer science principles and practices.
      • Skill in writing computer programs for various purposes.
  • Technologies:
    • Java
    • Custom Exceptions
    • Inheritance

3 Why Create Custom Exceptions?

Think about our TaskManager. What if a user tries to update a task that doesn’t exist? We could throw a generic exception, but that doesn’t tell the whole story. Is the task ID wrong? Was the task deleted by someone else?

By creating a TaskNotFoundException, the code immediately communicates the exact problem. This is incredibly valuable for debugging and for other developers who use your code. It makes the code cleaner and easier to maintain.

Custom exceptions allow you to create a vocabulary for the errors that can occur in your specific application.

4 Step 1: Define Your Custom Exception

Creating a custom exception is as simple as creating a new class that inherits from Exception (or one of its children). Let’s create one for the scenario where a task cannot be found.

Create a new file named TaskNotFoundException.java:

// TaskNotFoundException.java
public class TaskNotFoundException extends Exception {
    
    /**
     * Constructor that accepts an error message.
     * @param message A description of the error.
     */
    public TaskNotFoundException(String message) {
        // Pass the message up to the parent Exception class
        super(message);
    }
}

That’s it! You now have a custom exception.

5 Step 2: Throw Your Custom Exception

Now, let’s use our new exception. We’ll create a new method in TaskManager.java called findTaskById that throws our TaskNotFoundException if it can’t find the task.

// In TaskManager.java

/**
 * Finds a task by its ID.
 * @param taskId The ID of the task to find.
 * @return The found Task object.
 * @throws TaskNotFoundException if no task with the given ID is found.
 */
public Task findTaskById(int taskId) throws TaskNotFoundException {
  for (Task task : taskStore) {
    if (task.getId() == taskId) {
      return task; // Found it!
    }
  }
  // If the loop finishes, we didn't find the task. Throw our custom exception.
  throw new TaskNotFoundException("Task with ID " + taskId + " could not be found.");
}

Because TaskNotFoundException extends Exception, it is a “checked exception.” This means the Java compiler forces us to either handle it with a try-catch block or declare that our method throws it, as we did in the method signature.

6 Step 3: Catch and Handle the Custom Exception

Finally, let’s call our new method in App.java and handle the specific case where the task isn’t found.

// In App.java
public static void main(String[] args) {
  TaskManager manager = new TaskManager();
  manager.addTask(new Task("A real task", "A real description"));

  try {
    // --- Scenario 1: Find an existing task (should succeed) ---
    System.out.println("Searching for task with ID 1...");
    Task foundTask = manager.findTaskById(1);
    System.out.println("Success! Found task: " + foundTask.getTitle());

    // --- Scenario 2: Find a non-existent task (should fail) ---
    System.out.println("\nSearching for task with ID 99...");
    Task missingTask = manager.findTaskById(99);

  } catch (TaskNotFoundException e) {
    // This block will execute for Scenario 2
    System.err.println("Operation failed: " + e.getMessage());
  } catch (Exception e) {
    // A general catch-all for any other unexpected errors
    System.err.println("An unexpected error occurred: " + e.getMessage());
  }

  System.out.println("\nProgram execution continues...");
}

7 Your Turn: Create a DuplicateTaskException

Now it’s your turn to create another custom exception to handle a different business rule.

  1. Create a new custom exception class named DuplicateTaskException.java.
  2. Modify the addTask method in TaskManager. Before adding a new task, loop through the taskStore to see if any existing task already has the same title (you can use equalsIgnoreCase for a case-insensitive check).
  3. If you find a task with the same title, throw your new DuplicateTaskException.
  4. In App.java, add a try-catch block that demonstrates this new functionality. Try to add the same task twice and make sure you catch your DuplicateTaskException and print a user-friendly error message.

8 Reflect and Review

CautionReflection: 3-2-1
  • 3 Things I Learned: List three new concepts or skills you learned about creating and using custom exceptions.
  • 2 Things I Found Interesting: Mention two aspects of custom exceptions that you found particularly useful or interesting.
  • 1 Question I Still Have: Write down one question you have about checked vs. unchecked exceptions or another related topic.
ImportantCheck on Learning
  • In your own words, what is the main benefit of creating a TaskNotFoundException instead of just relying on a built-in exception?
  • What is the difference between a “checked” exception (extending Exception) and an “unchecked” exception (extending RuntimeException)? When might you choose one over the other?
  • How does using custom exceptions contribute to making a program more “self-documenting”?
Back to top