How to Create Custom Exception in Java

Introduction

Creating custom exceptions in Java allows you to define your own exception types for specific error conditions. This can help make your code more readable and maintainable by providing meaningful exception types that are relevant to your application's logic. Custom exceptions can extend the Exception class or the RuntimeException class, depending on whether you want them to be checked or unchecked exceptions.

Here is the tutorial to learn Exception Handling: Exception Handling in Java

Key Points:

  • Checked Exceptions: Extend the Exception class.
  • Unchecked Exceptions: Extend the RuntimeException class.
  • Custom Exception Classes: Should provide constructors to accept error messages and optionally, the cause of the exception.

Table of Contents

  1. When to Create Custom Exceptions
  2. Steps to Create Custom Exceptions
  3. Examples of Custom Exceptions
  4. Best Practices
  5. Real-World Example
  6. Conclusion

1. When to Create Custom Exceptions

You should consider creating custom exceptions when:

  • You need to represent specific error conditions that are not covered by existing Java exceptions.
  • You want to provide more meaningful error messages and handling logic specific to your application.
  • You need to encapsulate additional information about the error condition.

2. Steps to Create Custom Exceptions

Step 1: Define the Custom Exception Class

Decide whether your custom exception should be a checked or unchecked exception. Then, create a class that extends Exception (for checked exceptions) or RuntimeException (for unchecked exceptions).

Step 2: Provide Constructors

Provide constructors in your custom exception class to accept error messages and optionally, the cause of the exception.

Step 3: Throw the Custom Exception

Throw your custom exception in your code where appropriate.

3. Examples of Custom Exceptions

Example 1: Creating a Checked Custom Exception

public class InvalidAgeException extends Exception {
    // Constructor that accepts an error message
    public InvalidAgeException(String message) {
        super(message);
    }

    // Constructor that accepts an error message and a cause
    public InvalidAgeException(String message, Throwable cause) {
        super(message, cause);
    }
}

Example 2: Creating an Unchecked Custom Exception

public class InvalidInputException extends RuntimeException {
    // Constructor that accepts an error message
    public InvalidInputException(String message) {
        super(message);
    }

    // Constructor that accepts an error message and a cause
    public InvalidInputException(String message, Throwable cause) {
        super(message, cause);
    }
}

Throwing Custom Exceptions

public class CustomExceptionExample {
    public static void main(String[] args) {
        try {
            validateAge(15);
        } catch (InvalidAgeException e) {
            System.out.println("Exception caught: " + e.getMessage());
        }
    }

    public static void validateAge(int age) throws InvalidAgeException {
        if (age < 18) {
            throw new InvalidAgeException("Age must be 18 or older.");
        }
    }
}

Explanation:

  • InvalidAgeException: A custom checked exception that extends Exception.
  • InvalidInputException: A custom unchecked exception that extends RuntimeException.
  • validateAge(int age): Throws InvalidAgeException if the age is less than 18.

4. Best Practices

1. Use Meaningful Names

Name your custom exceptions meaningfully to indicate the error condition they represent.

Example:

public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

2. Provide Multiple Constructors

Provide constructors that accept error messages and optionally, the cause of the exception.

Example:

public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }

    public InsufficientFundsException(String message, Throwable cause) {
        super(message, cause);
    }
}

3. Document Your Exceptions

Document your custom exceptions using Javadoc comments to explain when and why they should be thrown.

Example:

/**
 * Exception thrown when there are insufficient funds in an account.
 */
public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

4. Avoid Catching Generic Exceptions

Avoid catching generic exceptions and rethrowing them as custom exceptions unless you add meaningful context.

Example:

try {
    // Some code that may throw exceptions
} catch (IOException e) {
    throw new CustomIOException("Error reading file", e);
}

5. Real-World Example

Let's create a real-world example to demonstrate creating and using custom exceptions.

Example:

public class BankAccount {
    private double balance;

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException("Insufficient funds. Available balance: " + balance);
        }
        balance -= amount;
    }

    public double getBalance() {
        return balance;
    }
}

public class RealWorldExample {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(100.0);

        try {
            account.withdraw(150.0);
        } catch (InsufficientFundsException e) {
            System.out.println("Exception caught: " + e.getMessage());
        }

        System.out.println("Current balance: " + account.getBalance());
    }
}

Explanation:

  • BankAccount: A class representing a bank account with methods to withdraw money and check the balance.
  • InsufficientFundsException: A custom exception thrown when there are insufficient funds in the account.
  • withdraw(double amount): Throws InsufficientFundsException if the withdrawal amount exceeds the balance.
  • RealWorldExample: Demonstrates creating a BankAccount instance, attempting to withdraw more than the available balance, and catching the custom exception.

6. Conclusion

Creating custom exceptions in Java allows you to define specific error conditions that can improve the readability and maintainability of your code. By extending Exception or RuntimeException, providing meaningful error messages, and following best practices, you can effectively use custom exceptions to handle errors in your application.

Summary of Key Points:

  • Checked Exceptions: Extend Exception.
  • Unchecked Exceptions: Extend RuntimeException.
  • Meaningful Names: Name your exceptions to reflect the error conditions they represent.
  • Multiple Constructors: Provide constructors for error messages and causes.
  • Document Exceptions: Use Javadoc comments to explain the purpose and usage of your custom exceptions.

Mastering the creation and use of custom exceptions can enhance the robustness and clarity of your Java applications.

Comments