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.