Monday, June 30, 2014

How to create Custom Exception in Java - Tutorial Example

Sometime we need to create custom Exception in Java, i.e. Exceptions which are not defined in JDK or any third party library your application is using. Though it’s widely recommended on several Exception best practices article, even Joshua Bloch has recommended in Effective Java to prefer standard exception over custom exception, sometime you really need it. There are certain guidelines to help to find whether you really need a custom exception or not. You should write your own exception classes if you answer yes to any of the following questions; otherwise, you can probably use someone else's.

  •     Do you need an exception type that isn't represented by those in the Java platform?
  •     Would it help users if they could differentiate your exceptions from those thrown by classes written by other vendors?
  •     Does your code throw more than one related exception?
  •     If you use someone else's exceptions, will users have access to those exceptions? A similar question is, should your package be independent and self-contained?


Custom Exception or Custom Message with Standard Exception?

For example if you declare an Exception that doesn't provide any useful information other than a custom name then it's probably use generic Exception class with a custom message as shown in below example :

public class DuplicateIDException extends Exception {}

This custom exception doesn't provide any extra information e.g. alternative ids, and that's why can be easily replaced by a custom message and standard Exception class, as shown below :

throw new Exception("ID already taken");

Even better, if you think the client code is not going to take any action other than logging if the id is already taken, throw a unchecked exception:

throw new RuntimeException("ID already taken");

Checked or Unchecked?

Once you make decision to create custom Exception, next thing is to decide on checked vs unchecked exception. As I said before, by default make your exception unchecked and you will find it whether it should be checked while writing client code. General guideline is to make an exception unchecked if the client code is not going to take any action other than logging.


How to create Custom Exception in Java - The Code

Here is our complete code example of creating custom or user defined Exception in Java.  In our example, we have created NoSuchProductException, which is thrown by methods returning products. This is an unchecked Exception as we made it to inherit from RuntimeException. It inherit getMessage() method from Throwable and also has a method getProductId() which returns product id for which this exception has caused. Don't make a Exception class as nested class even if its used only by one class, always declare Exceptions in their own class.

import java.util.HashMap;
import java.util.Map;

/**
 * Java Program to create custom exception and examples to show how to use
 * custom exception in Java.
 *
 * @author Javin Paul
 */
public class CustomExceptionDemo {

    private static final Map&lt;Integer, String&gt; products = new HashMap<>();

    static {
        products.put(100, "Coke");
        products.put(101, "KitKat");
        products.put(102, "Bisuits");
        products.put(103, "Toast");
    }

    public static void main(String args[]) {
        CustomExceptionDemo t = new CustomExceptionDemo();
        t.getProduct(1000);
    }

    public String getProduct(int id) {
        if (products.get(id) == null) {
            throw new NoSuchProductException("No such product exists", id);
        }
        return products.get(id);
    }
}

class NoSuchProductException extends RuntimeException {

    private int productId;

    public NoSuchProductException() {
        super();
    }

    public NoSuchProductException(String message, int productId) {
        super(message);
        this.productId = productId;
    }

    public NoSuchProductException(String message, int productId, Throwable cause) {
        super(message, cause);
        this.productId = productId;
    }

    @Override
    public String toString() {
        return super.toString();
    }

    @Override
    public String getMessage() {
        return super.getMessage() + " for productId :" + productId;
    }

    public int getProductId() {
        return productId;
    }
}

Output:
Exception in thread "main" NoSuchProductException: No such product exists for productId :1000
    at CustomExceptionDemo.getProduct(CustomExceptionDemo.java:26)
    at CustomExceptionDemo.main(CustomExceptionDemo.java:21)



Things to remember while creating Custom Exception in Java

Though creating a custom exception is as easy as sub-classing java.lang.Exception class, there are few best practices you can follow to make most of it. There is so much criticism of checked exception due to boiler plate require to handle it, you will hardly create your custom exception as checked.

1) Don’t' use Exception to control application behaviour. Exception handling is very expensive as it require native calls to copy stacktrace, each time exception is created.

2) While creating custom exception, prefer to create an unchecked, Runtime exception than a checked exception, especially if you know that client is not going to take any reactive action other than logging.

3) If your custom exception is created by passing another exception, then always contain original Exception as source; use constructor which takes Exception rather than only message String.

4) Apart from providing default no argument constructor on your custom Exception class, consider providing at least two more constructors, one which should accept a failure message and other which can accept another Throwable as cause.

5) If possible avoid creating custom Exception and re-use existing, standard Exception classes from JDK itself. Most of the time you will realize that all you need is a form of IllegalArgumentException or ParseException or something similar.

6) While defining custom Exception, one of the most common mistake programmer make is to think that constructor is inherited from java.lang.Exception class, for example they think that their Exception class will automatically inherit default no argument constructor and the one which takes a String message. This is not true. Constructor is not inherited in Java, not even default constructor. It's actually added by compiler rather than inherited from parent class. That's why I have declared two constructor, one with String parameter and other as Throwable parameter :

public NoSuchProductException(String message, int productId) {
        super(message);
        this.productId = productId;
    }

    public NoSuchProductException(String message, int productId, Throwable cause) {
        super(message, cause);
        this.productId = productId;
    }

This is actually standard way of creating custom Exception in Java. In order to save time, you can even create template of above class in Eclipse IDE.

7) For readable code, it's good practice to append the string Exception to the names of all classes that inherit (directly or indirectly) from the Exception class e.g. instead of naming your class IncorrectPassword, name it IncorrectPasswordException.


That's all about How to create custom Exception classes in Java. As I said, first try to avoid temptation of creating a brand new Exception class, think if you can reuse existing ones. If you absolutely need, then make sure to follow above best practices. At bare minimum, make effort to create unchecked exception rather than a checked one.

1 comment :

SARAL SAXENA said...

Hi Javin,

Nice article , just want to add a point to it..
All you need to do is create a new class and have it extend Exception.
If you want an Exception that is unchecked, you need to extend RuntimeException.

Note: A checked Exception is one that requires you to either surround the Exception in a try/catch block or have a 'throws' clause on the method declaration. (like IOException) Unchecked Exceptions may be thrown just like checked Exceptions, but you aren't required to explicitly handle them in any way (IndexOutOfBoundsException).

public class MyNewException extends RuntimeException {

public MyNewException(){
super();
}

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

Post a Comment