Java Custom Exception

Custom Exception

Custom exceptions, also known as user-defined exceptions, allow you to create your own exception classes to represent specific error conditions in your Java programs.

By extending the existing exception classes (Exception or RuntimeException), you can encapsulate meaningful information about the exceptional situation.

Custom exceptions in Java serve several important purposes and provide benefits that enhance the overall design, readability, and maintainability of your codebase.

Here’s why you might need to use custom exceptions:

Expressiveness and Clarity: Custom exceptions allow you to create exception classes with names that accurately describe specific error conditions in your application. This makes your code more expressive and self-documenting, improving its readability.

Semantic Meaning: Custom exceptions can have custom fields and methods that provide additional context and information about the exceptional situation. This helps developers understand the cause and context of the error.

Modular Design: By creating custom exceptions, you encapsulate error-handling logic and make it more modular. Each exception class can encapsulate error-specific behavior, promoting separation of concerns and maintainability.

Structured Error Handling: Custom exceptions enable you to handle different types of errors differently, enhancing your ability to react appropriately to various exceptional situations.

Centralized Error Handling: With custom exceptions, you can centralize error-handling logic in a consistent manner. You can create global catch blocks to handle specific types of custom exceptions, improving error management across the application.

API Design: When developing libraries or APIs, custom exceptions provide a well-defined way to communicate potential errors to users of your library. This helps users handle exceptions gracefully and handle specific error cases.

Diagnostic Information: Custom exceptions can include additional diagnostic information, such as error codes, timestamps, and more. This facilitates troubleshooting and debugging.

Testing: Custom exceptions make it easier to write unit tests for specific error scenarios, ensuring that your application behaves as expected in exceptional cases.

Enforcing Coding Standards: By creating custom exceptions, you enforce a consistent approach to handling errors across your codebase, making it easier for developers to follow best practices.

Localization and Internationalization: Custom exceptions can include localized error messages, allowing your application to provide user-friendly error messages in different languages.

Extensibility: Custom exceptions can be subclassed to create a hierarchy of exceptions that represent different levels of severity or specific error conditions.

Overall, custom exceptions provide a way to represent and handle errors in a more tailored and organized manner, making your codebase more maintainable, understandable, and robust.

Types of Exception

Types of Exception

Some of the Built-in Exceptions are tabulated below:

          Exception Class                     Description
ArithmeticException Occurs when an arithmetic operation is invalid, such as division by zero.
NullPointerException Thrown when an attempt is made to access or manipulate a null object.
ArrayIndexOutOfBoundsException Occurs when an array or collection is accessed using an index that is not valid.
IllegalArgumentException Thrown when an illegal argument is passed to a method.
ClassCastException Occurs when an inappropriate casting operation is performed on objects of incompatible types.
FileNotFoundException Thrown when an attempt to open a file fails due to the file not being found.
IOException Represents a wide range of I/O errors, such as reading/writing files, streams, etc.
SQLException Indicates database-related errors.
NumberFormatException Raised when a string cannot be converted to a numeric format.
ConcurrentModificationException Thrown when a collection is modified while being iterated.
IndexOutOfBoundsException General superclass for index-related exceptions.
RuntimeException Parent class for many unchecked exceptions.
NoSuchElementException Thrown when attempting to access an element that does not exist.

Need For Custom Exception:

Java’s built-in exception hierarchy includes a wide range of common exceptions that cover various programming scenarios. However, there are situations where it becomes necessary to enhance these standard exceptions with custom ones tailored to specific needs.

There are primary motives for introducing these custom exceptions:

  • Business Logic Exceptions: These exceptions pertain to the specific business logic and operational flow of an application. They offer clarity to both application users and developers by pinpointing the exact issue at hand.
  • Selective Handling of Existing Exceptions: Custom exceptions also enable the targeted capturing and specialized handling of certain existing Java exceptions.

To create a user-defined (custom) exception in Java, you need to create a new class that extends either the Exception class (for checked exceptions) or the RuntimeException class (for unchecked exceptions). Here’s the step-by-step process to create a user-defined exception:

java custom exception

1. Creating a User-Defined Checked Exception:

Custom checked exceptions are those that extend the java.lang.Exception class. They are considered checked because they must be either caught using a try-catch block or declared to be thrown using the throws keyword in the method signature where they might occur. These exceptions are typically used for scenarios where the code can reasonably recover from the exceptional situation.

Create a new Java class that extends the Exception class.

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

Use the constructor to set an error message for the exception.

2. Creating a User-Defined Unchecked Exception (Runtime Exception):

Custom unchecked exceptions, also known as runtime exceptions, extend the java.lang.RuntimeException class or its subclasses. They are unchecked because they do not need to be explicitly caught or declared to be thrown. They are generally used for situations that are caused by programming errors or unexpected conditions that the code might not be able to recover from.

Create a new Java class that extends the RuntimeException class.

public class CustomUncheckedException extends RuntimeException {
    public CustomUncheckedException(String message) {
        super(message);
    }
}

Use the constructor to set an error message for the exception.

3. Using the User-Defined Exception:

Once you’ve defined your custom exception, you can use it like any other exception in your code.

Here’s an example of how to use the custom exceptions:

public class Example {
    public static void main(String[] args) {
        try {
            throw new CustomCheckedException("Custom Checked Exception");
        } catch (CustomCheckedException e) {
            System.out.println("Caught Custom Checked Exception: " + e.getMessage());
        }

        try {
            throw new CustomUncheckedException("Custom Unchecked Exception");
        } catch (CustomUncheckedException e) {
            System.out.println("Caught Custom Unchecked Exception: " + e.getMessage());
        }
    }
}

In this example, we’ve created instances of both the custom checked and unchecked exceptions and thrown them within try blocks. The exceptions are then caught and handled with appropriate catch blocks.

Creating user-defined exceptions allows you to provide more specific error information and enhance the readability and maintainability of your code. It’s a useful practice when you need to handle specific error conditions that aren’t adequately represented by Java’s built-in exceptions.

Custom Unchecked Exception:

class CustomUncheckedException extends RuntimeException {
    public CustomUncheckedException(String message) {
        super(message);
    }
}
class TechVidvanExample{
    public static void main(String[] args) {
        try {
            processInput("invalid");
        } catch (CustomUncheckedException e) {
            System.out.println("Caught Custom Unchecked Exception: " + e.getMessage());
        }
    }
    public static void processInput(String input) {
        if (input.equals("invalid")) {
            throw new CustomUncheckedException("Invalid input encountered");
        }
        // Process the input
    }
}

Output:

Caught CustomUncheckedException: Invalid input encountered

Explanation:

We define a custom unchecked exception class, CustomUncheckedException, that extends RuntimeException. It has a constructor to set the error message. In the TechVidvanExample class, we have a processInput method that simulates processing user input.

If the input is “invalid”, we throw our custom unchecked exception. In the main method, we call processInput with “invalid” input. Since the input is indeed “invalid”, the customuncheckedexception is thrown. We catch the custom unchecked exception in a catch block and display its error message.

Custom Checked Exception:

// Define a custom checked exception by extending the Exception class

class CustomCheckedException extends Exception {
    public CustomCheckedException(String message) {
        super(message);
    }
}
class TechVidvanExample {
    // Method that may throw our custom checked exception
    public static void performOperation() throws CustomCheckedException {
        // Simulate a situation where our custom exception might occur
        boolean someCondition = true;
        if (someCondition) {
            throw new CustomCheckedException("Custom Checked Exception: Something went wrong");
        }
    }
    public static void main(String[] args) {
        try {
            performOperation();
        } catch (CustomCheckedException e) {
            System.out.println("Caught Custom Checked Exception: " + e.getMessage());
        }
    }
}

Output:

Caught Custom Checked Exception: Custom Checked Exception: Something went wrong

Explanation:

We define a custom-checked exception class, CustomCheckedException, that extends the Exception class. It has a constructor to set the error message. In the TechVidvanExample class, we have a method performOperation that simulates performing some operation.

If a certain condition is met (in this case, some condition is true), we throw our custom-checked exception using the throws clause. In the main method, we call performOperation() within a try-catch block to handle the custom-checked exception if it’s thrown.

Suppose you’re building a banking application and you want to handle the case where a user tries to withdraw more money from their account than their available balance. We can create a custom exception called InsufficientFundsException to represent this situation.

Example:

// Custom exception class for insufficient funds
class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

// BankAccount class representing a user's bank account
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 for withdrawal");
        }
        balance -= amount;
        System.out.println("Withdrawal successful. New balance: " + balance);
    }
}

// Main class representing the banking application
class BankingApp {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000.0);
        try {
            account.withdraw(1500.0); // Attempting to withdraw more than the balance
        } catch (InsufficientFundsException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

Error: Insufficient funds for withdrawal

Explanation:

We define a custom exception class InsufficientFundsException that extends Exception. It has a constructor to set the error message. The BankAccount class simulates a user’s bank account with a balance. The withdraw method attempts to withdraw an amount from the account.

If the withdrawal amount exceeds the balance, it throws the InsufficientFundsException.In the BankingApp class (representing the main application), we create an instance of BankAccount and attempt to withdraw an amount that exceeds the balance.

We catch the InsufficientFundsException in a catch block and display an appropriate error message. This example demonstrates how a user-defined exception (InsufficientFundsException) can be used to handle a specific error scenario in a real-world banking application.

Conclusion:

By leveraging the capabilities of custom exceptions, you elevate your error-handling practices to a higher level of clarity, efficiency, and user-friendliness.

They contribute to the overall robustness and reliability of your Java applications, helping you build code that is not only functional but also well-organized and maintainable.