Exercise 2.8: Creating Custom Exceptions
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
throwyour custom exception. - Written a
catchblock 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
throwa custom exception for a business rule violation. - Implement a
try-catchblock to handle the custom exception.
- Define a class that inherits from
- **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.
- 15-1251.00 - Computer Programmers:
- 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.
- Create a new custom exception class named
DuplicateTaskException.java. - Modify the
addTaskmethod inTaskManager. Before adding a new task, loop through thetaskStoreto see if any existing task already has the same title (you can useequalsIgnoreCasefor a case-insensitive check). - If you find a task with the same title,
throwyour newDuplicateTaskException. - In
App.java, add atry-catchblock that demonstrates this new functionality. Try to add the same task twice and make sure you catch yourDuplicateTaskExceptionand print a user-friendly error message.
8 Reflect and Review
- 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.
- In your own words, what is the main benefit of creating a
TaskNotFoundExceptioninstead of just relying on a built-in exception? - What is the difference between a “checked” exception (extending
Exception) and an “unchecked” exception (extendingRuntimeException)? When might you choose one over the other? - How does using custom exceptions contribute to making a program more “self-documenting”?