Exceptions

An exception is the occurrence of a detectable, abnormal situation which may lead to system failure. The occurrence of an abnormal event results in an exception being thrown. The code that handles the event catches the exception. Thus an exception results in a transfer of control: the processor stops executing the current sequence of statements, and resumes executing at a different point.

Exceptions classes

Exceptions are modeled in Java with the class java.lang.Exception. There are a number of Exception subclasses defined in the standard Java libraries. An important subclass is java.lang.RuntimeException. A RuntimeException is an unchecked exception. All other exceptions are checked exceptions. Basically, an unchecked exception is one that can occur "almost anywhere," while a checked exception will occur only in the context of a specific activity. For instance, the exception java.io.EOFException ("end of file" exception) is thrown if an input operation attempts to read a file or stream whose end has been reached. This exception is not a RuntimeException. It can only occur during an input operation. Checked and unchecked exceptions are further discussed below.

Note that exception classes can be extended by an application just like other library classes. For instance, an application might define a class

    public class PreconditionException extends RuntimeException ...

Throwing an exception

The following are typical events that cause exceptions to be thrown:

Executing any of the following code segments will result in an exception being thrown.

    int[] a = new int[10];
    a[10] = 0;          // 10 is not a legal index for a
     
    Object obj = new Object();
    String s = (String)obj;
                // obj is not a String and cannot be cast
                // to String
     
    Object obj = null;
    if (obj.equals(null))
                // obj is null; it does not reference an
                // object with an equals method.

An exception can also be thrown explicitly with a throw statement. The format is

    throw exception
     ;

For example,

    throw new Exception("My exception!");

Catching an exception

An exception is caught with a try statement. This statement has a rather baroque syntax. It consists of a try block, followed by one or more catch clauses, optionally followed by a finally clause.

The try block consists of the keyword try followed by a block:

    try {
statements and/or declarations
    }

A catch clause consists of the keyword catch followed by a parameter declaration in parentheses, and a block:

    catch ( parameterDeclaration
     ) {
statements and/or declarations
    }

A finally clause consists of the keyword finally followed by a block:

    finally {
statements and/or declarations
    }

A try statement is executed as follows.

Consider the following.

    try {
        i = i/i;
        j = 0;
        success = list.add(s);
        j = 1;
    } catch (ArithmeticException e) {
        j = 3;
    } catch (NullPointerException e) {
        j = 4;
    } catch (RuntimeException e) {
        if (e instanceof IllegalArgumentException)
            j = 6;
        else
            j = 5;
    } finally {
        System.out.println("The value of j is " + j);
    }

Execution of this statement begins with the execution of the statements of the try block:

    	i = i/i;
        j = 0;
        success = list.add(s);
        j = 1;

If these statements execute successfully, the catch clauses are ignored and the finally clause is executed. Output is

    The value of j is 1

If the value of i is initially 0, attempting to evaluate the expression i/i will cause an ArithmeticException to be thrown. This will be caught by the first catch clause, which assigns 3 to j. The finally clause prints

    The value of j is 3

If the first two statements of the try block complete successfully but the invocation of list.add(s) results in an IllegalArgumentException, this exception will be caught by the third catch clause. (An IllegalargumentException is neither an ArithmeticException nor a NullPointerException, but is a RuntimeException.) The finally clause writes

    The value of j is 6

Suppose that the invocation list.add(s) results in a OperationNotSupportedException being thrown. This exception is not a RuntimeException, so it will not be caught. The finally clause will write

    The value of j is 0

before the exception is propagated.

Propagating an exception

An exception is caught by a method only if it occurs inside a try block and the exception type matches one of the catch clause parameters. Otherwise, the exception is not caught. An exception thrown during execution of a method and not caught by the method is propagated to the method's caller. That is, the exception is thrown again at the point of invocation of the original method. Suppose methodA invokes methodB:

    public void methodA () {
        ...
        someClient.methodB();
        ...
    }

and that during the execution of methodB, an ArithmeticException is thrown. If methodB does not catch the exception, the ArithmeticException will be thrown again in methodA at the point at which methodB was invoked. If methodA does not catch the exception, the exception is thrown yet again in methodA's caller. Thus the exception propagates up the call chain until it is caught. If no method in the call chain catches the exception, the run time system terminates the program with an error message that might look something like this:

    java.lang.ArithmeticException: / by zero
                at Class4.methodB(Class4.java:36)
                at Class3.methodA(Class3.java:114)
                at Class2.start(Class2.java:29)
                at Class1.main(Class1.java:11)

Checked and unchecked exceptions

Unchecked exceptions are instances of the class java.lang.RuntimeException (or of its subclasses). All other exceptions are checked exceptions. The basic distinction is that a RuntimeException is one that can occur "almost anywhere," while a checked exception will occur only in the context of a specific activity.

If it is possible for a method to throw a checked exception, the exception must be listed in a throws clause that is part of the method heading. For instance, the method readLine() defined in the class java.io.BufferedReader is specified as

    public String readLine() throws IOException

where java.io.IOException is a checked exception. If the method skip() invokes this method, it must either catch the exception or also list the exception in a throws clause:

    public void skip () throws IOException {
        String s;
        s = input.readLine();
    }

Note that the "possibility" of throwing a checked exception is the syntactically possibility, not the logically possibility. Even if we can formally verify that an exception will not be thrown, the method must catch the exception or include a throws clause. For example, the method clone() is specified in the class Object as

    protected Object clone () throws CloneNotSupportedException

If a class implements the interface Cloneable, we are guaranteed that invoking this method for an instance of the class will not throw the exception. But, assuming the class does not override the method, invocations must still address the syntactic possibility that the exception might be thrown. If the following method populate did not include the try statement, it would be required to list CloneNotSupportedException in a throws clause:

    public class Sheep implements Cloneable {
        ...
        public void populate (Field myHome) {
            ...
            try {
                myField.add(this.clone());
            } catch (CloneNotSupportedException e) {
                // never will get here
                return;
            }
            ...
        }
        ...
    }

A throws clause can include any number of comma separated exceptions:

    public void getSomeData () throws IOException, NoDataException


Fred Hosch
Last modified: Tue Aug 7 08:15:17 CDT 2001