8.3 Custom Exceptions
Java provides hundreds of built-in exception classes out-of-the-box (like NullPointerException, FileNotFoundException, etc.), which cover most general error scenarios you'll encounter.
However, when developing real-world web services or enterprise applications, you often need to express highly specific error conditions unique to your business logic. Examples include an "Insufficient Balance Exception," an "Invalid Banned Word Input Exception," or a "Member Tier Too Low Exception."
When a developer creates a brand new exception class specifically for these scenarios, it is known as a Custom Exception.
1. Creating a Custom Exception
Creating your own custom exception is surprisingly simple in Java. You just need to inherit (extends) from either the built-in Exception class or the RuntimeException class.
- Inherit from
Exception: For creating strict errors (Checked Exceptions) that absolutely MUST be handled via atry-catchblock by anyone using your code. - Inherit from
RuntimeException:(Highly recommended in modern practice) For creating flexible errors (Unchecked Exceptions) that do not force the compiler to demand atry-catchblock everywhere.
Example: Writing an Insufficient Balance Exception
Let's imagine you are building a bank account withdrawal system. If the withdrawal amount is larger than the current balance, you need to throw an error.
// Inheriting RuntimeException to create an Unchecked Custom Exception
public class BalanceInsufficientException extends RuntimeException {
// 1. Default constructor
public BalanceInsufficientException() {
super("Insufficient balance."); // Setting a default error message
}
// 2. Constructor that accepts a custom error message
public BalanceInsufficientException(String message) {
super(message); // Pass the message up to the parent class constructor
}
}
2. Triggering Exceptions on Purpose: The throw Keyword
To put our custom exception to work, we must tell Java, "The error I just created has occurred!" when the prohibited condition is met. The keyword used to purposefully trigger an exception is throw.
Note: The block that handles an exception is
try-catch. The keyword that actively unleashes an exception isthrow.
public class Account {
private long balance; // Bank account balance
public Account(long balance) {
this.balance = balance;
}
public void withdraw(int money) {
// If the money requested is greater than the balance, throw our custom error!
if (this.balance < money) {
// Use the throw keyword to toss the newly created exception object
throw new BalanceInsufficientException("Insufficient balance: You need " + (money - this.balance) + " won more.");
}
this.balance -= money;
System.out.println(money + " won withdrawn. Remaining balance: " + this.balance);
}
}
3. Applying it in the Main Program
Now let's use the account model and the custom exception we just built.
public class CustomExceptionTest {
public static void main(String[] args) {
// Open a new account with 10,000 won
Account myAccount = new Account(10000);
try {
// Attempt to withdraw 3,000 won (This should succeed normally)
myAccount.withdraw(3000);
// Attempt to withdraw 20,000 won (This will trigger our custom error!)
myAccount.withdraw(20000);
} catch (BalanceInsufficientException e) {
// We can now uniquely catch our custom exception!
System.out.println("Withdrawal failed.");
// The error message will contain: 'Insufficient balance: You need 13000 won more.'
System.out.println("Reason: " + e.getMessage());
} catch (Exception e) {
System.out.println("An unknown, unexpected error occurred.");
}
}
}
[Execution Result]
3000 won withdrawn. Remaining balance: 7000
Withdrawal failed.
Reason: Insufficient balance: You need 13000 won more.
Why Use Custom Exceptions?
- Outstanding Readability: Returning
-1as an error code whenbalance < moneyis ambiguous. Throwingnew BalanceInsufficientException()makes it definitively clear to any developer exactly what went wrong. - Granular Control & Routing: Because the exception class name itself acts as a unique identifier for the type of error, you can create multiple
catchblocks dedicated to handling each specific business error delicately and accurately.
Congratulations! You have now mastered everything from the basics of averting a program crash to explicitly throwing your own logic-driven errors using Custom Exceptions. In the next chapter, we will finally explore the fundamental foundation of Java itself: the java.lang core package.