Effective Approach for Creating Custom Exceptions in Java

We have been using handling Java custom exceptions in our code for almost every industry standard application. The usual approach is to create some custom exception classes extending the base exception handling best practice which might make more sense.

1. Traditional Approach

Suppose we are creating a custom exception DBException for representing the exceptions that occurred during the database-related operations. Traditionally, we create a DBException class by extending Exception class.

public class DBException extends Exception {

  public DBException() {
    super();
  }

  public DBException(String message) {
    super(message);
  }

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

Now, every time we are caught in a situation where there is a need to throw a database-related exception, we usually create an instance of DBException, put some information in form of a message and throw it.

Now, let’s consider there are following situations we have identified in which we need to throw DBException:

  • SQL execution error
  • No data exist where we expect at least one row
  • Multiple rows exist where we expect only a single row
  • Invalid parameters error
  • and many more such cases

The problem with the above approach is that in catch block or in application code where these exceptions shall be handled, DBException does not provide enough information to handle each above-listed usecases, uniquely.

2. New Approach using Inner Classes

Our new approach uses static inner classes for every new exceptional scenario.

2.1. Create New Exception Types

Let’s solve the above problem with inner classes where we will create one class per use-case, and then group them inside DBException class.

Let us start with BaseException class which is created as an abstract and will be the superclass of all our exception classes.

public abstract class BaseException extends Exception {

  private String message;

  public BaseException(String msg) {
    super(msg);
    this.message = msg;
  }

  public String getMessage() {
    return message;
  }
}

Now it is time to create out new Exception inner classes.

public class DBException {

  //SQL execution error
  public static class BadExecution extends BaseException {

    public BadExecution(String msg) {
      super(msg);
    }
  }

  //No data exist where we expect at least one row
  public static class NoData extends BaseException {

    public NoData(String msg) {
      super(msg);
    }
  }

  //Multiple rows exist where we expect only single row
  public static class MoreData extends BaseException {

    public MoreData(String msg) {
      super(msg);
    }
  }

  //Invalid parameters error
  public static class InvalidParam extends BaseException {

    public InvalidParam(String msg) {
      super(msg);
    }
  }
}

Here, we created an inner class for each possible error scenario identified in starting. There can be many more extras. It depends on you only to identify and add more classes.

2.2. How to use custom exceptions?

Now to understand its usefulness, let’s create an exception and throw it. Then we will see the error message in the logs.

public class TestExceptions {
	public static void main(String[] args)
	{
		try
		{
			throw new DBExeption.NoData("No row found for id : x");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}

Program output:

com.exception.DBExeption$NoData: No row found for id : x
at com.test.TestExceptions.main(TestExceptions.java:7)

As you can see the log message in the exception stack trace has become more informative. It clearly tells what the error is. In the application code as well, you can check the instance of custom exception and handle it accordingly.

3. Advantages

  • The foremost advantage is that if the developer has written some doubtful message text, then also he can clearly observe what was actually wrong.
  • You can use instance-of comparison in different situations where you handle different exceptional scenarios.
  • You don’t need to send a single exception for a large set of exceptional conditions.
  • It is easy to write unit test cases for negative cases where you know the exact exception class, you should expect.
  • Logging is more meaningful and informative.

I hope this post about Java custom exceptions has been some information for you. If you have some suggestions, please write to me.

Happy Learning !!

Leave a Comment

  1. Creating specific exception types is good idea but grouping them in a Class is not better (at least for me). This is against design principle “Strong Cohession”. Are classes really intended for grouping types or it can be done better with packages ?

    Moreover, using inner classes leads to memory leaks !

    Reply
    • Packaging them in groups is also a good idea if developers are intelligent enough for using correct class in case of any exception.
      Memory leak? I don’t think so. Can you please elaborate more on memory leak issue?

      Reply
  2. Hey Lokesh,

    thanks for writing this article. Reminding developers of being mindful with exception handling is a good idea, as it’s too often done in a sloppy way.

    I have a few remarks though:

    * BaseException reinvents the wheel: the class “Exception” already has a way to store a message; no need to duplicate that in BaseException. Just pass the message parameter on to the superclass constructor.

    * BaseException has no constructor that takes a cause-exception (BaseException(String message, Throwable cause)). This is important in case you’re throwing a BaseException (or derived class) as a result of catching another exception. By specifying the original exception as cause, it’s much easier to debug what really happened as if you’re logging the stacktrace, you’ll get information about the inner exception as well.

    A good point you’re making is that having detailed exceptions is often more helpful than using one generic exception for everything. But there’s one thing I don’t get: why do you put them into DBException, as static inner classes? Why not just putting them top-level, without a wrapping class. You get exactly the same advantages of having detailed exceptions, without the weirdness of having so many inner classes.

    Reply
    • My intention is to group related exception classes in one class, just like we use packages. We can create some classes denoting broad exception categories and then use inner classes to create specific failure cases.

      Apart from above, code example is more to represent idea. Anyone can refine the code as per his/her need.

      Reply
      • correct me if I’m wrong, but aren’t you using the outer classes just to create a new namespace?

        why do you group your exceptions in one class and not a package? Is it to circumvent the Java restriction to have multiple classes in the same file?

        Reply
        • Yes, I am trying to create a logical namespace.

          You want to group them in package.. no problem..It will still be beneficial.. at least more than having a generic exception for a group of failures.

          Reply
          • Yeah, that is (at least for me) the main point here: Create exceptions that are meaningful and describe the problem well enough.

  3. Don’t you think this will create classes for each and every static inner class, which is a huge, if we keep on adding for every error one static class. Pls let me know if am wrong and suggest me..

    Reply
    • Yes, effort is more than usual. But rewards are far better. Believe me, I have used this technique in one project and it works like a charm. Also, you do not need to teach every tiny detail of exception handling logic to team members, most of the things are self-explanatory. This is highly recommended if you are building a product which you will be managing for 5-10 years.

      Reply
      • although there are many classes created, but still I believe these classes are accessible just like a method on an object with out a need to create an object for it, other than the parent class like as you shown “new DBExeption.NoData(“No row found for id : x”);”, which will not load JVM with more objects.

        But, I have a doubt, if the growing no of errors increases to support “Logging is more meaningful and informative.”, does that not make the object huge for jvm.

        what happens if there are many scenarios and you created/covered all those in your product/application, where u create an object every time, for exception handling, making JVM fully loaded with many huge DBExeption objects.

        So, do we have to make this “DBExeption” class a singleton?

        Pls let me know if am wrong with my assumption.

        Reply
        • If such thing happen when there are plenty of exceptions all the time, then application will crash anyway. No fault of object creation logic or JVM load.
          Regarding singleton. I believe we should treat exception objects as first class citizen in our application. If there is an exception occurred, let’s have a fresh new exception object and populate it with complete context information. They have same importance in your application as much DTO objects.
          “DBExeption class as a singleton?”. Need thorough review but its possible.

          Reply
        • Please never, ever try to use singletons as exceptions! Here’s why:
          * When an exception instance is created, its constructor (the one in class Throwable) automatically captures the stack trace, so you can later (e.g. in a log) find out where excactly the exception was thrown.
          If you’re reusing exception instances, you lose this information. You will always get the stacktrace showing where the instance was originally created, giving you now way to find out where it was actually thrown.

          Regarding your worries about memory:
          Exception instances are not huge. Maybe you are worried about the size of the class DBException in this example. But there’s no need to be. First of all, you’ll not throw instances of this class, but only of its inner classes (which again are rather small). Second, With static inner classes, there’s no real connection between the outer and the inner class. In fact, on the level of the classloader, there’s nearly no difference between a static inner class and a “normal” class.
          And third: exception instances are usually short-lived, so the garbage collector will remove them pretty soon.

          In the end, I think you’ll never see a case where an application runs into out-of-memory problems because of exceptions.

          Reply
          • Thanks(Rolf Schäuble) for a detailed Information.

            Also, I would like to know in a real time scenario, how and when actually the JVM triggers the grabage collector. is there any specific config changes that we have to do on JVM for this.

Leave a Comment

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode