Skip to main content

Custom (User-Defined) Exceptions

Java provides a vast array of built-in exceptions like NullPointerException and ArithmeticException. However, sometimes these standard exceptions do not accurately describe the specific business logic errors occurring in your application.

In such cases, you can create User-Defined Exceptions (also known as Custom Exceptions).


Why Create Custom Exceptions?

  1. Business Logic Clarity: To catch and provide specific treatment to a subset of existing Java exceptions based on business rules.
  2. Custom Error Codes: You can add specific attributes (like error codes or transaction IDs) to your custom exception class for better logging and monitoring.
  3. Readability: InsufficientFundsException is much easier to understand in a banking application than a generic Exception or RuntimeException.

How to Create a Custom Exception

To create a custom exception, you simply need to create a class that extends either:

  • Exception: To create a Checked Exception (the compiler forces you to handle it).
  • RuntimeException: To create an Unchecked Exception (handling is optional).

Step 1: Create the Exception Class

Usually, a custom exception class should provide at least a default constructor and a constructor that accepts a String message.

// Extending Exception makes this a Checked Exception
public class InvalidAgeException extends Exception {

// Default constructor
public InvalidAgeException() {
super("Age is not valid");
}

// Parameterized constructor
public InvalidAgeException(String message) {
super(message);
}
}

Step 2: Throw the Custom Exception

Use the throw keyword to throw the exception when your business rule is violated. Because it's a checked exception, you must also use throws in the method signature.

public class LabException7 {

// Method throws the custom exception
static void validateAge(int age) throws InvalidAgeException {
if (age < 18) {
throw new InvalidAgeException(
"Not eligible to vote. Age must be 18 or older."
);
} else {
System.out.println("Welcome to the voting system.");
}
}

public static void main(String args[]) {
try {
// Calling the method requires a try-catch block
validateAge(15);
} catch (InvalidAgeException e) {
System.out.println("Caught Custom Exception: " + e.getMessage());
}
}
}

Output:

Caught Custom Exception: Not eligible to vote. Age must be 18 or older.

Custom Exception with Error Codes

You can enhance your custom exceptions by adding fields and methods, such as an error code.

public class PaymentFailedException extends RuntimeException {

private int errorCode;

public PaymentFailedException(String message, int errorCode) {
super(message);
this.errorCode = errorCode;
}

public int getErrorCode() {
return errorCode;
}
}
public class LabException8 {

static void processPayment(double amount) {
if (amount > 10000) {
// Throwing unchecked custom exception
throw new PaymentFailedException("Amount exceeds daily limit", 4001);
}
System.out.println("Payment Successful");
}

public static void main(String args[]) {
try {
processPayment(15000);
} catch (PaymentFailedException e) {
System.out.println("Transaction Failed!");
System.out.println("Reason: " + e.getMessage());
System.out.println("Error Code: " + e.getErrorCode());
}
}
}

[!NOTE] Since PaymentFailedException extends RuntimeException, we did not need to declare throws PaymentFailedException in the method signature.