Java Custom Exceptions

In this tutorial, we’ll cover how to create a custom exceptions in Java. We will look at how custom exceptions are created for both checked and unchecked exceptions.

Why We Need Java Custom Exceptions

To understand why we might need Java custom exceptions we first need to consider that the Java SDK comes with many different types of exceptions that cover potential erroneous situations that can occur when programming Java Code.

However, sometimes we need to create custom Java exceptions that supplement the standard Java exceptions. Some of the reasons for doing this include:

  • We may be using a framework that requires us to create custom java exceptions to handle certain concerns in a specific way such as transaction handling.
  • The Java projects, custom Java API’s that we create might require custom exceptions to make our code more cohesive, understandable and maintainable.
  • The Java application might contain business logic which requires a custom exception to handle a specific error related to the problem domain.

As you probably already know Java exceptions can be both checked and unchecked. So lets see how we can create custom exceptions in Java to manage these scenarios.

Custom Checked Exception

Checked exceptions are exceptions which we have to handle explicitly in our code. For example the below code shows that we need to explicitly handle the checked exception or our code will not compile.

1
2
3
4
5
try {
    FileInputStream is = new FileInputStream(getFileFromResources("file.txt"));
} catch (IOException e) {
    e.printStackTrace();
}   

In the above code we have to handle the checked IOException explicitly. From the above code we have a utility method:

1
getFileFromResources("file.txt")

which is a utility method that we use to look up a Java resource with the name file.txt. However, if we make a design decision that we require the client to explicitly catch an exception if the resource file.txt is not found we can create our own custom checked exception to handle this scenario.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class ResourceNotFoundExceptionChecked extends Exception {

    public ResourceNotFoundExceptionChecked (String message) {
        this(message, null);
    }
    public ResourceNotFoundExceptionChecked (Throwable cause) {
        this(null, cause);
    }
    public ResourceNotFoundExceptionChecked (String message, Throwable cause) {
        super(message, cause);
    }
}

Now we will create a new version of our getFileFromResources method to throw our new custom checked exception

1
2
3
4
5
6
7
8
9
public static File getFileFromResourceChecked(String fileName) throws ResourceNotFoundExceptionChecked  {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    URL resource = classLoader.getResource(fileName);
    if (resource == null) {
        throw new ResourceNotFoundExceptionChecked("File Not Found");
    } else {
        return new File(resource.getFile());
    }
}

As you can see from the above code we create a new method getFileFromResourceChecked this method has to declare explicitly that it throws our new custom checked exception ResourceNotFoundExceptionChecked. Moreover, in the body of the method we throw the Java checked exception to notify the client that the resource could not be found.

We also must update our client code to explicitly catch the custom checked exception or the code will not compile.

1
2
3
4
5
6
7
public static void main(String[] args) {
    try {
        getFileFromResource_Checked("file-does-not-exist.txt");
    } catch(ResourceNotFoundExceptionChecked e) {
        System.err.println("File Not Found");
    }
}

Custom Unchecked Exception

In the last section we saw how to create a custom checked exception if the resource could not be found. However, sometimes we don’t want to create a custom Java exception that must be handled explicitly and in fact new programming languages such as Kotlin do not have checked exceptions. This is because checked exception have some of the following disadvantages:

  • They add tight coupling between the different modules / layers of an application. For example if the programming language of choice only supports checked exceptions and if a piece of code is changed to introduce a new custom checked exception then any code that uses that code must be updated to handle that new exception type. Moreover, things get worse if the client code simply throws that exception then any dependent code is required to be updated causing a chain reaction, and reducing the maintainability of code.
  • Custom checked exceptions can break the API of a component, causing a breaking change requiring all clients of that component to be updated.

Let’s create a new custom unchecked exception to indicate that a resource could not be found.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public lass ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        this(message, null);
    }
    public ResourceNotFoundException(Throwable cause) {
        this(null, cause);
    }
    public ResourceNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

The implementation of our new unchecked custom exception looks almost identical to the checked custom exception the only difference is that our unchecked custom exception extends from RuntimeException and not Exception. With our custom exception class created lets create a new version of the getFileFromResource method.

1
2
3
4
5
6
7
8
9
public static File getFileFromResource(String fileName) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    URL resource = classLoader.getResource(fileName);
    if (resource == null) {
        throw new ResourceNotFoundException("File Not Found");
    } else {
        return new File(resource.getFile());
    }
}

The getFileFromResource method is updated above to throw our new unchecked custom java exception ResourceNotFoundException. We notice that we no longer need to declare the custom exception explicitly in the throw clause of the method, thus simplifying any client code.

1
2
3
public static void main(String[] args) {
    getFileFromResourceUnChecked("file-does-not-exist.txt");
}

As we can see the client code no longer has to handle the custom exception ResourceNotFoundException explicitly unless it wants to. In this case if the ResourceNotFoundException is not handled it will propagate up the call stack unless it is handled or if the exception is not handled it will terminate the program.

Conclusion

Java Custom exceptions are very useful when we wish to handle specific errors related to the code we write that is not covered by the standard Java API’s. Custom Java exceptions when used properly can serve to improve the serviceability of an application – error handling and logging.

In this tutorial we also looked at some of the advantages and disadvantages of creating checked and unchecked custom exceptions.