Often you will find it useful to define and throw your own exceptions, in addition to using the pre-defined Exception subclasses.
Here is an example of defining your own exception by simply subclassing Exception.
class MyException extends Exception {
}
Creating Custom Exceptions in Java SE 17
In Java, exceptions are objects that represent errors or unexpected behavior during program execution. Java SE 17 allows you to define your own custom exceptions by extending the `Exception` class for checked exceptions or the `RuntimeException` class for unchecked exceptions.
1. Steps to Create a Custom Exception
Extend the Exception or RuntimeException class
Provide constructors
(Optional) Add custom methods or fields
2. Example: Creating a Custom Checked Exception
A checked exception requires explicit handling using `try-catch` or `throws` in method signatures.
Example: `InvalidAgeException`
// Custom checked exception (extends Exception)
class InvalidAgeException extends Exception {
// Constructor with a custom message
public InvalidAgeException(String message) {
super(message);
}
}
Usage of `InvalidAgeException`
class Voter {
// Method that checks if age is valid for voting
public void checkEligibility(int age) throws InvalidAgeException {
if (age < 18) {
throw new InvalidAgeException("Age must be 18 or above to vote.");
} else {
System.out.println("You are eligible to vote.");
}
}
public static void main(String[] args) {
Voter voter = new Voter();
try {
voter.checkEligibility(16); // This will throw InvalidAgeException
} catch (InvalidAgeException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
}
Output:
Exception caught: Age must be 18 or above to vote.
3. Example: Creating a Custom Unchecked Exception
An unchecked exception extends `RuntimeException` and does not require explicit handling.
Example: `InsufficientFundsException`
// Custom unchecked exception (extends RuntimeException)
class InsufficientFundsException extends RuntimeException {
public InsufficientFundsException(String message) {
super(message);
}
}
Usage of `InsufficientFundsException`
class BankAccount {
private double balance;
public BankAccount(double balance) {
this.balance = balance;
}
// Withdraw method that throws unchecked exception
public void withdraw(double amount) {
if (amount > balance) {
throw new InsufficientFundsException("Insufficient funds: Balance is " + balance);
}
balance -= amount;
System.out.println("Withdrawal successful. Remaining balance: " + balance);
}
public static void main(String[] args) {
BankAccount account = new BankAccount(500);
account.withdraw(600); // This will throw InsufficientFundsException
}
}
Output:
Exception in thread "main" InsufficientFundsException: Insufficient funds: Balance is 500.0
4. Key Differences Between Checked and Unchecked Exceptions
Feature
Checked Exception (extends Exception)
Unchecked Exception (extends RuntimeException)
Needs try-catch or throws
Yes
No (Optional)
Compiler enforcement
Yes
No
Typically used for
Recoverable errors (e.g., missing file)
Programming errors (e.g., division by zero)
5. Best Practices for Custom Exceptions
Use checked exceptions for recoverable issues (e.g., invalid input, missing files).
Use unchecked exceptions for programming logic errors (e.g., null references, out-of-bounds access).
Provide meaningful exception messages to help debugging.
Use standard Java exceptions (e.g., IllegalArgumentException) before creating custom ones unless a unique business rule is needed.
Creating a Custom Checked Exception
You can subclass java.lang.Exception (or any of its subclasses) to define custom exceptions.
To create custom checked exceptions, subclass java.lang.Exception or its subclasses (which are not subclasses of RuntimeException).
Let us revisit the exception classes in figure 5-6
Figure 5-6: Hierarchy of Exception and Error classes
A word of caution here: even though you can extend class java.lang.Throwable to create your own exceptions, it is not recommended. Class Throwable is the superclass of classes java.lang.Error and java.lang.Exception.
The exception handler for this class will catch all types of errors and exceptions! For example, say an OutOf-MemoryError brings the JVM into an unstable state. Catching it as a subclass of Error or Throwable would be undesirable and potentially dangerous.
Obviously, you may not want this behavior. Note: Do not extend class java.lang.Throwable to create your own exceptions, even though you can. Class Throwable is the superclass of classes java.lang.Error and java.lang.Exception. The exception handler for this class will catch all types of errors and exceptions.
FileReader Constructor Exception
What will be the output of trying to compile and run the following piece of code? Assume that the file xyz.txt exists at the given location.
import java.io.*;
public class Test {
public static void main(String [] args) {
FileReader fr1 = new FileReader(new File("xyz.txt"));
FileReader fr2 = new FileReader(new File("xyz.txt"));
System.out.println(fr1.equals(fr2));
}
}
Compilation fails
Compilation Succeeds but an Exception is thrown at runtime
Compilation Succeeds and prints true at runtime
Compilation Succeeds and print false at runtime
Answer: a
Explanation:
The FileReader constructor throws a FileNotFound Exception which is a checked exception.
Since this exception is not handled or thrown by the main method, the compilation will fail.
Square Root Application - Exercise
In this exercise, you will modify SquareRoot so that it responds appropriately if the user inputs a negative number. Square Root Application - Exercise