Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
57: Creating Custom Exceptions
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
CriticalTemperatureExceptionthat extendsException. - Add a private field
double temperatureto the exception class. - Create a constructor that accepts a
String messageand thedouble temperature. - Create a method
getTemperature()to retrieve the value. - Write a class
GreenhouseMonitorwith a methodcheckTemperature(double currentTemp). IfcurrentTempis greater than 40.0, throw your custom exception. - In a
mainmethod, callcheckTemperature(45.5)inside a try-catch block and print a message that includes the temperature retrieved from the exception object.
There are no comments for now.