Main Page

Previous Next

Defining Your Own Exceptions

There are two basic reasons for defining your own exception classes:

  • You want to add information when a standard exception occurs, and you can do this by rethrowing an object of your own exception class.

  • You may have error conditions that arise in your code that warrant the distinction of a special exception class.

However, you should bear in mind that there's a lot of overhead in throwing exceptions, so it is not a valid substitute for 'normal' recovery code that you would expect to be executed frequently. If you have recovery code that will be executed often, then it doesn't belong in a catch block, rather in something like an if-then-else loop.

Let's see how to create our own exceptions.

Defining an Exception Class

Your exception classes must always have Throwable as a superclass, otherwise they will not define an exception. Although you can derive them from any of the standard exceptions, your best policy is to derive them from the Exception class. This will allow the compiler to keep track of where such exceptions are thrown in your program, and check that they are either caught or declared as thrown in a method. If you use RuntimeException or one of its subclasses, the compiler checking for catch blocks of your exception class will be suppressed.

Let's go through an example of how you define an exception class:

public class DreadfulProblemException extends Exception {
  // Constructors
  public DreadfulProblemException(){ }      // Default constructor

  public DreadfulProblemException(String s) {
    super(s);                        // Call the base class constructor

This is the minimum you should supply. By convention, your exception should include a default constructor and a constructor that accepts a String object as an argument. The message stored in the superclass, Exception (in fact in Throwable, which is the superclass of Exception), will automatically be initialized with the name of your class, whichever constructor for your class objects is used. The String passed to the second constructor will be appended to the name of the class to form the message stored in the exception object.

Of course, you can add other constructors. In general, you'll want to do so, particularly when you're rethrowing your own exception after a standard exception has been thrown. In addition, you'll typically want to add instance variables to the class that store additional information about the problem, plus methods that will enable the code in a catch block to get at the data. Since your exception class is ultimately derived from Throwable, the stack trace information will be automatically available for your exceptions.

Throwing Your Own Exception

As we saw earlier, we throw an exception with a statement that consists of the keyword throw, followed by an exception object. This means you can throw your own exception with the statements:

DreadfulProblemException e = new DreadfulProblemException();
throw e;

The method will cease execution at this point - unless the code snippet above is in a try or a catch block with an associated finally clause; the contents of which will be executed before the method ends. The exception will be thrown in the calling program at the point where this method was called. The message in the exception object will only consist of the qualified name of our exception class.

If you wanted to add a specific message to the exception, you could define it as:

DreadfulProblemException e = new DreadfulProblemException("Uh-Oh, trouble.");

We're using a different constructor here. In this case the message stored in the superclass will be a string which consists of the class name with the string passed to the constructor appended to it. The getMessage() method inherited from Throwable will, therefore, return a String object containing the string:

"DreadfulProblemException: Uh-Oh, trouble."

You can also create an exception object and throw it in a single statement. For example:

throw new DreadfulProblemException("Terrible difficulties");

In all the examples, the stack trace record inherited from the superclass, Throwable, will be set up automatically.

An Exception Handling Strategy

You should think through what you want to achieve with the exception handling code in your program. There are no hard and fast rules. In some situations you may be able to correct a problem and enable your program to continue as though nothing happened. In other situations outputting the stack trace and a fast exit will be the best approach - a fast exit being achieved by calling the exit() method in the System class. Here we'll take a look at some of the things you need to weigh up when deciding how to handle exceptions.

Consider the last example where we handled arithmetic and index-out-of-bounds exceptions in the method, divide(). While this was a reasonable demonstration of the way the various blocks worked, it wasn't a satisfactory way of dealing with the exceptions in the program, for at least two reasons. First, it does not make sense to catch the arithmetic exceptions in the divide() method without passing them on to the calling method. After all, it was the calling method that set the data up, and only the calling program has the potential to recover the situation. Second, by handling the exceptions completely in the divide() method, we allow the calling program to continue execution, without any knowledge of the problem that arose. In a real situation this would undoubtedly create chaos, as further calculations would proceed with erroneous data.

We could have simply ignored the exceptions in the divide() method. This might not be a bad approach in this particular situation, but the first problem the calling program would have is determining the source of the exception. After all, such exceptions might also arise in the calling program itself. A second consideration could arise if the divide() method was more complicated. There could be several places where such exceptions might be thrown, and the calling method would have a hard time distinguishing them.

An Example of an Exception Class

Another possibility is to catch the exceptions in the method where they originate, then pass them on to the calling program. You can pass them on by throwing new exceptions that provide more granularity in identifying the problem (by having more than one exception type, or by providing additional data within the new exception type). For example, you could define more than one exception class of your own that represented an ArithmeticException, where each reflected the specifics of a particular situation. This situation is illustrated here.

Click To expand

This shows how two different circumstances causing an ArithmeticException in method2(), are differentiated in the calling method, method1(). The method, method2(), can either throw an exception of type Exception1, or of type Exception2, depending on the analysis that is made in the catch block for the ArithmeticException type. The calling method has a separate catch block for each of the exceptions that may be thrown.

You could also define a new exception class that had instance variables to identify the problem more precisely. Let's suppose that in the last example, we wanted to provide more information to the calling program about the error that caused each exception in the divide() method. The primary exception can be either an ArithmeticException or an ArrayIndexOutOfBoundsException, but since we're dealing with a specific context for these errors we could give the calling program more information by throwing our own exceptions.

Let's take the ArithmeticException case as a model and define our own exception class to use in the program to help identify the reason for the error more precisely.

Try It Out - Define Your Own Exception Class

We can define the class which will correspond to an ArithmeticException in the method divide() as:

public class ZeroDivideException extends Exception {
  private int index = -1;      // Index of array element causing error

  // Default Constructor
  public ZeroDivideException(){ }

  // Standard constructor
  public ZeroDivideException(String s) {
    super(s);                              // Call the base constructor

  public ZeroDivideException(int index) {
    super("/ by zero");                    // Call the base constructor
    this.index = index;                    // Set the index value

  // Get the array index value for the error
  public int getIndex() {
    return index;                          // Return the index value

How It Works

As we've derived the class from the class Exception, the compiler will check that the exceptions thrown are either caught, or identified as thrown in a method. Our class will inherit all the members of the class Throwable via the Exception class, so we'll get the stack trace record and the message for the exception maintained for free. It will also inherit the toString() method which is satisfactory in this context, but this could be overridden if desired.

We've added a data member, index, to store the index value of the zero divisor in the array passed to divide(). This will give the calling program a chance to fix this value if appropriate in the catch block for the exception. In this case the catch block would also need to include code that would enable the divide() method to be called again with the corrected array.

Let's now put it to work in our first TryBlockTest code example.

Try It Out - Using the Exception Class

We need to use the class in two contexts - in the method divide() when we catch a standard ArithmeticException, and in the calling method, main(), to catch the new exception. Let's modify divide() first:

public static int divide(int[] array, int index) throws ZeroDivideException {
  try {
    System.out.println("First try block in divide() entered");
    array[index + 2] = array[index]/array[index + 1];
    System.out.println("Code at end of first try block in divide()");
    return array[index + 2];

  } catch(ArithmeticException e) {
    System.out.println("Arithmetic exception caught in divide()");
    throw new ZeroDivideException(index + 1);  // Throw new exception
  } catch(ArrayIndexOutOfBoundsException e) {
                "Index-out-of-bounds index exception caught in divide()");
  System.out.println("Executing code after try block in divide()");
  return array[index + 2];

The first change is to add the throws clause to the method definition. Without this we'll get an error message from the compiler. The second change adds a statement to the catch block for ArithmeticException exceptions that throws a new exception.

This new exception needs to be caught in the calling method main():

public static void main(String[] args) {
  int[] x = {10, 5, 0};              // Array of three integers

  // This block only throws an exception if method divide() does
  try {
    System.out.println("First try block in main()entered");
    System.out.println("result = " + divide(x,0));  // No error
    x[1] = 0;                        // Will cause a divide by zero
    System.out.println("result = " + divide(x,0));  // Arithmetic error
    x[1] = 1;                        // Reset to prevent divide by zero
    System.out.println("result = " + divide(x,1));  // Index error

  } catch(ZeroDivideException e) {
    int index = e.getIndex();        // Get the index for the error
    if(index > 0) {                  // Verify it is valid and now fix the array
      x[index] = 1;                  // ...set the divisor to 1...
      x[index + 1] = x[index - 1];   // ...and set the result
      System.out.println("Zero divisor corrected to " + x[index]);

  } catch(ArithmeticException e) {
    System.out.println("Arithmetic exception caught in main()");
  } catch(ArrayIndexOutOfBoundsException e) {
    System.out.println("Index-out-of-bounds exception caught in main()");
  System.out.println("Outside first try block in main()");

How It Works

All we need to add is the catch block for the new exception. We need to make sure that the index value for the divisor stored in the exception object is positive so that another exception is not thrown when we fix up the array. As we arbitrarily set the array element that contained the zero divisor to 1, it makes sense to set the array element holding the result to the same as the dividend. We can then let the method main() stagger on.


A point to bear in mind is that the last two statements in the try block will not have been executed. After the catch block has been executed, the method continues with the code following the try-catch block set. In practice you would need to consider whether to ignore this. One possibility is to put the whole of the try-catch block code in main() in a loop that would normally only run one iteration, but where this could be altered to run additional iterations by setting a flag in the catch block.

This is a rather artificial example - so what sort of circumstances could justify this kind of fixing up of the data in a program? If the data originated through some kind of instrumentation measuring physical parameters such as temperatures or pressures, the data may contain spurious zero values from time to time. Rather than abandon the whole calculation you might well want to amend these as they occurred, and press on to process the rest of the data.

Previous Next
JavaScript Editor Java Tutorials Free JavaScript Editor