EXCEPTION HANDLING

CONTENTS

1. Introduction
2. The Throwable class hierarchy
3. "Catching" an exception (and "try" blocks)
4. Multiple catch blocks
5. Creating your own exceptions class
6. Searching for a catch block


1. Introduction

An exception is an event that occurs during program execution which makes further execution impossible. Standrad examples are divide by zero error and arithmetic overflow (there are many more). An exceptions handleris piece of code that gets invoked when an exception is encountered. This then allows the program to either "fix" what ever caused the exception, or abort execuition "gracefully". Java comes with a set of exception handlers which, in the event of an exception, output an appropriate error message and then cause program execution to "gracefully" terminate. The code presented in Table 1 divides two numbers, if the second number is a 0 a divide by zero excetion will be generated (as illustrated in Table 2).

// EXCEPTION GENERATOR APPLICATION
// Frans Coenen
// Wednesday 24 March 1999
// University of Liverpool

import java.io.*;

class ExceptionGeneratorApp {

    // ---------------------- FIELDS ------------------
    
    public static InputStreamReader input         = new InputStreamReader(System.in);
    public static BufferedReader    keyboardInput = new BufferedReader(input);
		
    // --------------------- METHODS ------------------

    /* Main method  */

    public static void main(String[] args) throws IOException {

        // Input two integers

	int input1 = new Integer(keyboardInput.readLine()).intValue();
	int input2 = new Integer(keyboardInput.readLine()).intValue();

        // Divide first by second and output result

        System.out.println("Division = " + input1/input2);
	
        // End

        System.out.println("END"); 
        }
    }

Table 1:Exception generator

$ java ExceptionGeneratorApp
4
2
Division = 2
END

$ java ExceptionGeneratorApp
4
0
java.lang.ArithmeticException: / by zero
        at ExceptionGeneratorApp.main(ExceptionGeneratorApp.java:30)            

Table 2: Sample output



2. THE Throwable CLASS HIERARCHY

In Java an exception is treated as an instance of the class java.lang.Throwable or some sub-class of this class. A Class Hierarchy diagram illustrating some of the significant exception handling classes and their inter-relationships is presented in Figure 1.

Figure 1. Class Hierarchy Still to do

From Figure 1 we can see that the class Throwable has two immediate sub-calsses, Error and Exception, both of which are extended by many further sub-classes. The distinction between the two is the Error calss deals with exceptional events from which it is generally not possible to recover, e.g. out of memory error; whilst the Exception class deals mostly with events from which it is possible to recover, such as divide by zero error (one of the Exception sub-classes is the class ArithmeticException). Note also that the class IOException, used in the code presented in Table 1, is a sub-class of the Exception class.

NOTE: In the code presented in Table 1, instead of writing:

public static void main(String[] args) throws IOException

we could have written:

public static void main(String[] args) throws Exception

because IOException is a sub-class of Exception (Figure 1).



3. "CATCHING" AN EXCEPTION (AND "TRY" BLOCKS)

The exceptions handlers provided with java do not provide for recovery, after having issued a warning execution is abandoned. To instigate a recovery process the programmer must cause the method in which the exception occurs to catch the exception. We do this by including a catch block in our code. This has the form:

catch(ExceptionClass ec) {
   .....
   }

For example to "catch" an arithmetic exception of the form generated by the code presented in Table 1:

catch(ArithmeticException error) {
    .....
    }

A catch block is only entered if a detetected exception is of the same type as its argument (which must be some sub-class of the class Throwable). Note that an instance of the class ArithmeticException is also an instance of the class RuntimeException, Exception and so on (Figure 1).

Once we have caught an exception, one of the things we might like to do is output a warning the an exception has been found. To do this we can make use of the methods defined in the class Throwable. One of these is the toString method which returns a short description of "this" throwable object. Thus we can write a catch block as follows:

catch(ArithmeticException error) {
    System.out.println("\nOwn exception " + error.toString() + " caught");
    }  

To use a catch block we also requires something called a try block. This has the form:

try {
   .....
   }

and delimits the the part of a method from where it is possible to invoke the catch block. The try block must immediately precede its associated catch block. Thus, with respect to the code presented in Table 1 we might include the try block as follows:

try {
    // Divide first by second and output result
    System.out.println("Division   = " + input1/input2);
    }

Thus, given the code presented in Table 1, we can include a catch and try block as shown in Table 3. Some sample output in table 4 is presented in Table 4, note that we continue processing one the exception has been cuaght (i.e. we recover) as evidanced by the END output.

// OWN EXCEPTION GENERATOR APPLICATION
// Frans Coenen
// Friday 26 March 1999
// University of Liverpool

import java.io.*;

class OwnExceptionGeneratorApp {

    // ---------------------- FIELDS ------------------
    
    public static InputStreamReader input         = 
                new InputStreamReader(System.in);
    public static BufferedReader    keyboardInput = 
                new BufferedReader(input);
		
    // --------------------- METHODS ------------------

   /* Main method  */

    public static void main(String[] args) throws IOException {  
        
	// Input two integers
	    
	int input1 = new Integer(keyboardInput.readLine()).intValue();
	int input2 = new Integer(keyboardInput.readLine()).intValue();
        
	// Try block

	try {
            // Divide first by second and output result
            System.out.println("Division   = " + input1/input2);
            }
	
	// Catch block

        catch(ArithmeticException error) {
            System.out.println("\nOwn exception " + error.toString() + " caught");
            }
	
	// End

        System.out.println("END");
	}
    }

Table 3:Catch and try block example

  
$ java OwnExceptionGeneratorApp
4
2
Division   = 2
END

$ java OwnExceptionGeneratorApp
4
0

Own exception java.lang.ArithmeticException: / by zero caught
END                             

Table 4: Sample output



4. MULTIPLE CATCH BLOCKS

When writtiong our own exceptions handlers we are mot limitted to single catch blocks, we can include as many as we like. For example in the code presented in Table 2 we can include a second catch block to catch (say) an IOException. This will of course necitate a redefinition of the try block. The code is presented in Table 5 together with some sample output in Table 6.

// OWN EXCEPTION GENERATOR APPLICATION
// Frans Coenen
// Friday 26 March 1999
// University of Liverpool

import java.io.*;

class OwnExceptionGeneratorApp {

    // ---------------------- FIELDS ------------------
    
    public static InputStreamReader input         = new InputStreamReader(System.in);
    public static BufferedReader    keyboardInput = new BufferedReader(input);
		
    // --------------------- METHODS ------------------

   /* Main method  */

    public static void main(String[] args) throws IOException {  

        // Try block

	try {
	    // Input two integers
	    
	    int input1 = new Integer(keyboardInput.readLine()).intValue();
	    int input2 = new Integer(keyboardInput.readLine()).intValue();

            // Divide first by second and output result

            System.out.println("Division   = " + input1/input2);
            }
	
	// Catch arithmetic exception

        catch(ArithmeticException error) {
            System.out.println("\nOwn exception " + 
	    		error.toString() + " caught");
            }

        // Catch number format exception
        
        catch(NumberFormatException error) {
            System.out.println("\nOwn exception " + 
	    		error.toString() + " caught");
            }
	    
	// End

        System.out.println("END"); 
	}
    }

Table 5:Multiple catch blocks

 
java OwnExceptionGeneratorApp
4
2
Division   = 2
END

$ java OwnExceptionGeneratorApp
4
0

Own exception java.lang.ArithmeticException: / by zero caught
END

$ java OwnExceptionGeneratorApp
4
x

Own exception java.lang.NumberFormatException: x caught
END                                   

Table 6: Sample output

As an alternative to the code presented in Table 5, we may define a single catch block whose parameter is a super-class of all the exceptions we wish to catch amd include within the catch block some code to identify the particular exception we have caught. To do this we can make use of the instanceof operator. Thus:

catch(Exception error) {
    if (error instanceof ArithmeticException) System.out.println("\nOwn arithmetic exception " + 
    			error.toString() + " caught");
    else {
	if (error instanceof NumberFormatException) System.out.println("\nOwn number format exception " + 
			error.toString() + " caught");
        else System.out.println("\nOwn other exception " + error.toString() + " caught");
	}
    }

Note: When working with multiple catch blocks make sure that the class type for each block is not a super-class. If you need to use a super-calss make sure that it appears at the end of the sequence!



5. CREATING YOUR OWN EXCEPTION CLASS

Given a particular application we may wish to create our own exception class, for example we might wish to create an exception class NegativeNumberException which is a sub-class of RuntimeException. If we look at the Throwable class this has two constructors (Figure 1), one with no arguments and ome witn a string argument. If we use the first of these to crearte an instancec of the Class Throwable:

Throwable myException = new throwable();

the statement:

System.out.println(myException.toString())

will cause the instance name myException to be output. If we use the second constructor, for example:

Throwable myException = new throwable("Instance of Throwable");

the statement:

System.out.println(myException.toString())

will cause the output: myException: Instance of Throwable

to be produced. The statement:

System.out.println(myException.getMessage())

will output Instance of Throwable (or null if no error message has been supplied, i.e. when the default constructor is used).

If you examome the sub-classes of the class Throwable, most of them do not add any further functionality other than redefining the constructors. Thus our desired NegativeNumberException might be defined as follows:

class NegativeNumberException extends RuntimeException {

    // --------------------- CONSTRUCTOS ---------------------
    
    public NegativeNumberException() {
    	super();
	}
	 
    public NegativeNumberException(String errorMessage) {
    	super(errorMessage);
	}
    }

To throw an exception we require a throws statement. This has the form:

throw < ExeptionObject >

and is usually coupled with a slection state ment of some form (if-else, case). Thus to throw an instance of our NegativeNumberException might write:

throw new NegativeNumberException();

or:

throw new NegativeNumberException("Input must be a positive number"); 

The above is incoporated into some appropriate code as illustrated in Table 7 (example output in Table 8). Note that the code includes a call to the printStackTrace method contained in the Throwable class. This dispalys the names of the methods that are visited by the JVM in search of an appropriate catch block.

// OWN EXCEPTION GENERATOR VERSION 3 APPLICATION
// Frans Coenen
// Monday 29 March 1999
// University of Liverpool

import java.io.*;

/***********************************************/
/*                                             */
/*          NEGATIVE NUMBER EXCEPTION          */
/*                                             */
/***********************************************/

class NegativeNumberException extends RuntimeException {

    // --------------------- CONSTRUCTOS ---------------------
    
    public NegativeNumberException() {
    	super();
	}
	 
    public NegativeNumberException(String errorMessage) {
    	super(errorMessage);
	}
    }
    
/*********************************************************/
/*                                                       */
/*          OWN EXCEPTIOPN GENWERATOR VERSION 3          */
/*                                                       */
/*********************************************************/    

class OwnExcepGenVer3App {

    // ---------------------- FIELDS ------------------
    
    public static InputStreamReader input         = new InputStreamReader(System.in);
    public static BufferedReader    keyboardInput = new BufferedReader(input);
		
    // --------------------- METHODS ------------------

   /* Main method  */

    public static void main(String[] args) throws IOException {          

	// Input two integers
	    
	int input1 = new Integer(keyboardInput.readLine()).intValue();
	int input2 = new Integer(keyboardInput.readLine()).intValue();
	
        // Try block
       
        try {
            if (input1 < 1 || input2 < 1) throw new NegativeNumberException("Input " +
 				"must be a positive number");
				 	
	    // Divide first by second and output result
	    
	    System.out.println("Division   = " + input1/input2);
	    }
            	
	// Catch block
	
	catch(NegativeNumberException error) {
	    error.printStackTrace();
	    }
		    
	// End

        System.out.println("END"); 	    
	}
    }

Table 7:Own exception

 
$ java OwnExcepGenVer3App
4
2
Division   = 2
END

$ java OwnExcepGenVer3App
0
2

NegativeNumberException: Input must be a positive number
END

$ java OwnExcepGenVer3App
4
0

NegativeNumberException: Input must be a positive number
END                  

Table 8: Sample output

Note: A throws clause lists the exceptions that can be thrown by a method, for example:

public static void main(String[] args) throws IOException

This is not the same thing as a throws statment!



6. SEARCHING FOR A CATCH BLOCK

The code presented in Table 9 (taken from Holmes (1998)) shows a chain of method calls culminating in a throws statement. The "stack trace" is presented in Table 10. Note how Java searches back through the method calls to find an appropriate catch block.

// OWN EXCEPTION GENERATOR VERSION 4 APPLICATION
// Frans Coenen
// Tuesday 28 March 2000
// University of Liverpool

import java.io.*;

/***********************************************/
/*                                             */
/*                OWN EXCEPTION                */
/*                                             */
/***********************************************/

class OwnException extends RuntimeException {

    // --------------------- CONSTRUCTOS ---------------------
    
    public OwnException() {
    	super();
	}
    }
    
/*********************************************************/
/*                                                       */
/*          OWN EXCEPTIOPN GENWERATOR VERSION 3          */
/*                                                       */
/*********************************************************/    

class OwnExcepGenVer4App {
		
    // --------------------- METHODS ------------------

   /* Main method  */

    public static void main(String[] args) { 
	
        // Try block
       
        try {
            methodA();
	    }
            	
	// Catch block
	
	catch(OwnException error) {
	    error.printStackTrace();
            }	    
	}

    /* Method A */
    
    public static void methodA() throws OwnException {
        methodB();
	}

    /* Method B */
    
    public static void methodB() throws OwnException {
        methodC();
	}

    /* Method C */
    
    public static void methodC() throws OwnException {
        throw new OwnException();  
	} 		
    }

Table 7:Own exception

 
$ java OwnExcepGenVer4App
OwnException
        at OwnExcepGenVer4App.methodC(OwnExcepGenVer4App.java:65)
        at OwnExcepGenVer4App.methodB(OwnExcepGenVer4App.java:59)
        at OwnExcepGenVer4App.methodA(OwnExcepGenVer4App.java:53)
        at OwnExcepGenVer4App.main(OwnExcepGenVer4App.java:40) 

Table 10: Stack trace



REFERENCES

  1. Holmes, B. (1998). Programming with java. Jones and Bartlett, London, p338.



Created and maintained by Frans Coenen. Last updated 28 March 2000