r EXCEPTION HANDLING

EXCEPTION HANDLING


1. OVERVIEW

During program execution exceptional events may occur making normal continuation undesirable or even impossible. Such exceptional occurances can arise as a result of errors; for example attempted division by zero or erroneous user input. Many modern programming languages provide facilities for handlinf exceptions as part of the langaughe, Java is such a language (another is Ada). Other language, for example C, leave the onus of dealing with exceptions entirely with the programmer.

Conside the code given in Table 1, if we input a letter instead of an integer or if the second input is a zero then an exception will result. Some sample output is presented in Table 2. The table shows three calls to the ExceptionGeneratorApp program. The first call generates no eceptions. The second generates a arithmetic exception. Note that the output tells the user:

  • The name of the merthod and class in which the exception occured.
  • The name of the source file used to produce the executable.
  • The line number in the source code --- line 31 in the exmaple).

The third call then generates an number format excdption --- because we have entered a charcater (the lower case leter 'o' in this case).

// 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 {  
        int input1, input2;

        // Input two integers

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

        // Divide first by second and output result

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

Table 1: Simple program that may generate exceptions


$ java ExceptionGeneratorApp
4
2
Division = 2

[frans@frans Exceptions]$ java ExceptionGeneratorApp
4
0
java.lang.ArithmeticException: / by zero
        at ExceptionGeneratorApp.main(ExceptionGeneratorApp.java:31)

$ java ExceptionGeneratorApp
o
java.lang.NumberFormatException: o
        at java.lang.Integer.parseInt(Integer.java)
        at java.lang.Integer.(Integer.java)
        at ExceptionGeneratorApp.main(ExceptionGeneratorApp.java:26)
[frans@frans Exceptions]$    

Table 2: Example output generated from progarm given in Table 1


2. EXCEPTION HANDLER

An exception handler is a piece of code that is automatically inoked when an exception occurs to ensure that appropriate action is taken to prevent the program from "crashing". There are two broad possible courses of action:

  1. Cause program to terminate "cleanly".
  2. take some remedial action so that processing can continue.

The choice will depend on the nature of the exception.

When an exception occurs this is detected by the Java interpreter (as ilustrated in the fore going section), we say that the interpreter has caught the exception. As a result of "catching" an exception an exception is thrown. From the users point of view this means that, by default, the program will terminate and some error message produced. We have already come across the concept of exceptions when using the read and readLine methods. Examination of these methods in the BufferedReader class indicates that they both throw an IOException (look in the method details listed half way down on the JDK BufferedReader WWW page!). Hence whenever we use read or readline in a method such as main we must state that the method throws an IOException.

So far we have let the Java interpreter handle the catching of exceptions automatically, however we can include code in a class to explicitly handle exceptions in a way more in tune with the nature of a particular application.


3. EXCEPTION CLASSES

Not suprisingly an exception in Java is an object like any other object. More specificaly an exception is an instance of a sub-calls of the class Throwable (Fgure 1). Note that from Figure 1 the class Throwable has two immediate sub-classes, Error and Exception. Both are super calsses of a number of further sub-class. For example, as shown in the figure, Exception is a super-class of RuntimeException, which in turn is a super-class of ArithmeticException and IllegalArgumentException (amongst others), and so on. The first occurs in the event of a divide by zero error, and the second if we miss type a number --- for example include a letter o instead of the number 0.

CLASS DIAGRAM SHOWUNG API EXCEPTIONS CLASSES

Fig 1: Class diagram showing API exceptions classes


3. CATCHING EXCEPTIONS (TRY AND CATCH BLOCKS)

If we wish to catch exceptions explicitly, instead of allowing the Java interpreter to do it automatically, then we must include a catch block and a try block in our code. A catch block in the method where we expect the exception to occure. A catch block is a method nested within another method which has a single parameter whose type is any sub-class of the class throwable. The catch block must be placed at the end opf the method in which it is contained just before the terminating '}' for that metghod. A try block delimits the part of a method in which a particular catch block is applicable. A try block moust always immediately preceed a catch block, the latter being entered when an exception is encountered within that try block. A try block may refer to a sequence of catach blocks (but there must be at least one).

The code in Table 3 includes two catch blocks, one for arithmetic exceptions and one for number f ormat exceptions. The toString() method is a Throwable instance method to convert an object to a string (a similar method exists in many other classes in the API such as the Integer class and other numeric "wrapper" classes.

// 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 {  
        int input1, input2;

        // Try block

	try {
	    // Input two integers
	    
	    input1 = new Integer(keyboardInput.readLine()).intValue();
	    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");
            }
	}
    }

Table 3: Example program with the inclusion of catch blocks

Any particular catch block is only entered if an instance of the appropriate class indicated by the formal parameter associated with that block is encountered or some sub-class of that class. Thus catch(ArithmeticException error) will be entered when an arithmetic exception is encountered. If we had a catch block of the form:

Note that when several catch blocks are included in a method make sure that they are all on the same level in the calss hierarchy, i.e. one is not a super-class of another, otherwise the Java interpreter will not know which catch block to enter. If you have to include a super-class, possibly because to act as a "catch-all" for exceptions not explicitly considered, then this catch block should be the last in the sequence.

Some sample output fro this program is given in Table 4.

$ java OwnExceptionGeneratorApp
4
2
Division   = 2
$ java OwnExceptionGeneratorApp
4
0

Own exception java.lang.ArithmeticException: / by zero caught
$ java OwnExceptionGeneratorApp
o

Own exception java.lang.NumberFormatException: o caught  

Table 4: Sample output from program given in Table 3

An alternative implementation to the above may comprise a single catch block whose formal parameter is a super-class of all the exceptions that are likely to occure in the method. To identify specific exceptions within this catch block we can then make use of the instanceof Java operator to compare the input instance with specific classes. Some appropriate code to this end is presented in Table 5.

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

import java.io.*;

class OwnExcepGenVer2App {

    // ---------------------- 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 {  
        int input1, input2;

        // Try block

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

            // Divide first by second and output result

            System.out.println("Division   = " + input1/input2);
            }
	
	// Catch block
	
	catch(Exception error) {
            if (error instanceof ArithmeticException)
                System.out.println("\nOwn exception " + error.toString() + " caught");
            if (error instanceof NumberFormatException)
                System.out.println("\nOwn exception " + error.toString() + " caught");
            }
	}
    }

Table 5: Alternative encoding for program given in Table 3


4. PROGRAMMER DEFINED EXCEPTIONS (AND throw STATEMENTS)

It is sometimes desirable to create your own exception class. This can be done by simply extendiong one of the existing classes. Such a class will of course inherit all the public and protected characteristics of its parent classes. Examination of the "exceptiomns" classes will show that (eith the exception of the class throwable) they tend to contain just two constructors and no fields or methods. For example the class IllegalArgumentException comprises:

public IllegalArgumentException();
public IllegalArgumentException(String message);

The second is used where wish to attach our own message. Let us suppose we wish to create an exception class NegativeNumberException which extends the class IllegalArgumentException. We would do this as follows:

class NegativeNumberException extends RuntimeException {

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

Rember that the super keyword causes constructors in super classes to be invoked. We can now create instances of this class in the normal manner. For example:

NegativeNumberException newException = 
	NegativeNumberException("Input must be a positive number");

Note the inclusion of the error message. As a result the statement:

System.out.println(error.toString());

Will produce output of the form:

NegativeNumberException: Input must be a posetive number    

4.1 The throws statement

Tests to check for the predefined Java exception classes are already included as standrad, we do not have to write these ourselves. However, if we create our own exceptions class we must also expressly check for the particular condition that will generate the exception and the expressly cause the exception to be thrown. The required testing normally takes the form of a Bollean expression forming part of a simple "if" statement. If the condition is identified we must then cause the xception to be "thrown" using a throw statement. For example we might write:

if (input1 < 1) {
    NegativeNumberException newException = 
	    NegativeNumberException("Input must be a positive number");
    throw newException;
    }

or more concisely:

if (input1 < 1) {
    throw new NegativeNumberException("Input must be a positive number");
    }

A short program, on the same theme as those presented in Tables 1, 3 and 5, is given in Table 6 which puts all the above together.

// 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(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 {  
        int input1, input2;

        // Try block

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

            // Check input

            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) {
            System.out.println("\n" + error.toString());
            }
	}
    }

Table 6: Example program with the inclusion of own exception class and a throw statement




Created and maintained by Frans Coenen. Last updated 02 August 1999