Exceptions   
Peter Komisar   ©  Conestoga College  
minor revision 5.1  /  2006


Exception Hierarchy



Exception handling is a plan for changing a program's flow of control
when an
unexpected event or error occurs. Control is diverted to a part
of the program
which communicates with the user. Exceptions are
thrown by unacceptable
conditions, such as dividing an integer by
zero or trying to access an array
element outside of it's defined bounds.

// Exceptions are thrown by unacceptable conditions arising

Like most everything in Java, exceptions are handled using an object-
based
model. Program problems are encapsulated in class objects. When
an exception
occurs, an Exception object is created, specifically, one of
many specialized
descendants of Throwable, signaling to the program it
has a problem to deal
with.

// Descendants of Throwable are created in response to error conditions

The programmer can choose to deal with an exception using a 'try...catch'
construct or it can pass the exception on up, (the call stack) all the way to
main( ). If main doesn't handle the exception, the program will halt with an
error report explaining what happened.

// Different tactics may be used in dealing with exceptions shown below

The figure below shows the inheritance relationships that exist between
Throwable and
it's descendants. The tree describes two branches. There
is the Error branch
and the Exception branch. The Exception branch is
subclassed to form the
various checked exceptions. The Exception class
is subclassed by the
RuntimeException exception class which is the
parent of the various runtime
exceptions.

The hierarchy essentially describes three groups of exceptions. Errors,
runtime exceptions and checked exceptions. A more detailed diagram
is
provided below the figure. Notice even the detailed diagram doesn't show

all the exception classes used in the JDK. There are also special Exception

classes (i.e.SQLException) defined inside packages devoted to particular
topics. It makes sense to house these specialized Exception class
types with
the packages that use them.
 

The Exception Hierarchy

                                            Object
                                                |
                                         Throwable
                                        /                 \
                          Exception       Error
                             /                      \
  RuntimeException      The various checked exceptions
               /                             ( ClassNotFoundException, InterruptedException etc. )
The various runtime exceptions
( ArithmeticException, ArrayStoreException, BufferOverflowException etc. )

 
 

Exception Hierarchy Tree

// Abbr. from JDK  documentation. The Throwable hierarchy is in java.lang package

    Object
         |
 Throwable
         |
         |__Error
         |__Exception
         |
         |__ClassNotFoundException
         |__CloneNotSupportedException
         |__IllegalAccessException
         |__InstantiationException
         |__InterruptedException
         |__NoSuchFieldException
         |__NoSuchMethodException
         |
         |__________RuntimeException
                                        |
                                        |__ArithmeticException
                                        |__ArrayStoreException
                                        |__ClassCastException
                                        |__IllegalArgumentException
                                        |                      |__IllegalThreadStateException
                                        |                      |__NumberFormatException
                                        |
                                        |__IllegalMonitorStateException
                                        |__IllegalStateException
                                        |__IndexOutOfBoundsException
                                        |                    |__ArrayIndexOutOfBoundsException
                                        |                    |__StringIndexOutOfBoundsException
                                        |
                                        |__NegativeArraySizeException
                                        |__NullPointerException
                                        |__SecurityException
                                        |__UnsupportedOperationException
 

// The Throwable hierarchy is all in java.lang package  Throwable is parent to
// Exception and Error. Exception class includes checked and runtime exceptions
 


Checked & Runtime Exceptions & Errors



Checked Exceptions 
// expected errors that may happen in a correct program

Checked exceptions arise in a correct program from problems arising
during a program's use. A user might make a typing error and enter a
number where a letter should be located. A power failure might cause
an interruption in a network socket connection causing an IOException
to be thrown. These are types of error a programmer can expect to occur
and needs to be ready to handle.

If a situation arises that may cause a checked exception to be raised
but the programmer hasn't provided some code to handle the exception
the compiler will report the problem to the programmer. For instance the
compiler might report something like, "java.lang.SomeKindOfException
must be caught or declared to be thrown."  The following example won't
compile. The compiler reports InterruptedException must be caught.


Example

class CheckEx{
     public static void main(String args[]){
         Thread.sleep(1000);
         }
     }          // doesn't compile. reports InterruptedException
 


Runtime Exceptions  

Runtime exceptions are thrown by what are commonly called program
bugs. A typical example of this is when a loop is used that incorrectly
references an array element that is beyond the range of elements that
have been defined. For instance, an attempt is made to access the
tenth array element in an array that only has nine elements. This will
cause an ArrayOutOfBounds exception to be thrown.

// bugs that show up at runtime need to be fixed by the programmer

In a correct program, runtime exceptions should never occur so you
are not required to handle them. It is assumed the programmer will fix
any problems that cause these runtime exceptions to occur. In the
case of runtime exceptions, they show up and reported when the
program is run. Runtime exceptions are often harder to repair as they
can result from what is correct code from the compilers point of view.
The code is correct in the sense it logical leads to the result that causes
the runtime exception to be thrown. To show the 'Array Out of Bounds'
problem the following sample compiles fine but at runtime throws an
ArrayOutOfBounds exception. 


Example   
class ArrayBug{

                         public static void main(String args[]){
                               float [ ]  f={ 1.01f  };
                               System.out.println( f[1] );
                               }
                         }   

// compiles but fails to run. ArrayOutOfBounds exception is thrown


Errors

Errors describe environmental problems which may be rare or difficult
to recover from such as running out of computer memory. You are not
expected to handle Error class objects. These should be regarded as
environmental flaws. Hopefully you will never see them.



User Defined Exceptions and the throw Statement



Before we look at the error handling strategies Java supplies, we will
look at how a programmer can take control of when an exception is
thrown using the keyword throw. As well, we need to consider that
Java is an object-oriented environment. Even exceptions are defined
as classes that are used as templates to create exception objects.
This opens the possibility for the Java programmer to use inheritance
to define custom exception classes.

Custom exception classes are created by extending Exception class.
The programmer can use the 'throw' keyword in conjunction with the
given exception class constructor to generate objects of this class in
response to certain circumstances. Exceptions are thrown implicitly
when something illegal has occurred in a program. In contrast,
exceptions are thrown explicitly with the keyword 'throw'.

// the 'throw' keyword together with object-oriented inheritance allows
// custom exceptions to be created

In the following example, a custom exception class called PartyException
is created by extending Exception. This exception object is thrown, in
the BirthdayCalendar call if some birthday condition is met. ( This is
not good coding in the sense that exception handling is there to handle
when things go wrong and not to do a sort of flow control as is exampled
below. )

Example

class PartyException extends Exception{
    PartyException( ){
    System.out.println("Time for a party");
    }
   }
 // PartyException extends Exception & prints to console its "Time for a party"

class BirthdayCalendar{
  public static void main(String[] args) throws PartyException {
          // to get pass the compiler we show main throwing the exception
          //   Assume we have a list we loop through, itemizing  friend and and family birthdays
          //   Also assume the current date (plus some advance time) is compared to the list
          //    of birthdates.  If one is found,  a boolean value, a_birthday, is set to true
             if (a_birthday)  throw  new PartyException( );
         }
      }

The 'throw' keyword is used in conjunction with the PartyException
class constructor and the 'new' operator. Also, the suffix, 'throw
PartyException' has been appended to the main methods signature.
This was necessary in order for the code to compile. This satisfies
the rule that states a method that may cause an exception to be thrown
must be defined showing explicitly which exception it can throw.

// checked exceptions must be caught - runtime exceptions may be caught

(Notice we didn't have to add a throws clause to main when we were
dealing with
the ArithmeticException. This is because ArithmeticException
is a runtime exception. As was
discussed earlier, the programmer is not
mandated to catch runtime exceptions. Not
to say it would not have
been a good idea!

By the way, nothing stops us from catching runtime exceptions.
We will example this later in the note.
 


Error Handling Strategies



There are three strategies one can describe when dealing with exceptions.
The first is more a lack of strategy, 'Don't do anything at all!'. It is possible
to take this approach and you get the expected results. The second is to
defer dealing with the exception to a higher scope. The second approach
may be described as passing the problem on. The final strategy is to use
'try catch and finally' blocks to handle the occurrence of exceptions.

1. Do Nothing

The first case scenario in dealing with exceptions is to do absolutely
nothing! The Java compiler only allows you to get away with this with
RunTime and Error exceptions. This is not a wise approach but is
included more as a demonstration of the simplest scenario. The
following example shows an exception waiting to happen.


Example
 
      
class Trouble{

               public static void main(String[] args) {
                        int x =1 / 0;
                        System.out.println("We will never see this line printed");
                       }
                  }    

// this will compile but an exception will be thrown by the runtime environment

Observe the class provides no plan to deal with the inevitable exception
it is set to create. In this case the exception is thrown in the main( )
method. Since main is the program's point of entry, it doesn't have far
to go before being registered as an exception with the user. The
Exception object is created and passed to the runtime which prints an
error report to console stating an ArithmeticException has been thrown
and exits the program. If you look at detailed class exception hierarchy
described earlier you will find the RuntimeException subclass,
ArithmeticException, listed.

 

  Dividing by zero with floating point numbers


  /* Floating point numbers will not throw the runtime ArithmeticException. Instead
      as mandated by the IEEE floating point standard a floating point number reports 
      INFINITY when a divide by zero using floating point numbers is performed.  */ 

  class X1{
               public static void main(String[] args) {
                System.out.println("Div Test");
                double s=60;
                double t=0;
                double d = s / t;
                System.out.println(d);  // prints 'Infinity'
                }
         } 



2. Pass the Exception On with a 'throws' Statement

The keyword throw causes an exception to be thrown. The keyword
throws
is used differently. This keyword is appended to a method's
signature to show the method is capable of throwing an exception.
The throws clause declares that the use of the given method may
result in an exception (of the type declared) being thrown. This
exception, if it is not handled by appropriate code locally, will be
passed 'up' into the next highest scope containing this method call.

The following example shows how a throws clause is appended to
a method signature.

public static void sleep(long millis) throws InterruptedException

// The sleep( ) method is a static Thread class method. It has a
// couple overloaded
forms. The commonest form takes an int
// value representing milliseconds.


Any method that throws an exception (and does handle the exception
itself ) must
be itself declare it throws that exception. In the following
example, the rest method
is defined calling sleep within it. ( Notice it
calls the static method sleep, off of the
Thread class name. This is
good form as it signals the reader that sleep is a static
method.)


      
public void rest( ) throws InterruptedException{
               Thread.sleep(60000);
              // sleep might be interrupted and throw InteruptedException
                }


Because sleep can throw an InterruptedException, the compiler now
requires the
enclosing method, rest( ), to declare it throws this
exception. If rest( )
is now called in another method that method too
must be declared as throwing InterruptedException and so on all the
way up to main( ). There is an alternative. The new methods can be
written to handle any exceptions that occur.

This approach is useful in defining one or a set of methods that may
cause an exception to be thrown. In the final analysis you will need
to use Java's technique for handling exceptions using try catch and
finally blocks.

 

3. Handle the Exception with try catch & finally blocks

The recourse Java provides for disposing or handling exceptions that
may occur in a program are structures built using 'try catch and finally'
blocks. Any method that may throw an exception  is 'called' from
inside the try block. A catch block is provided to handle the exception
should that exception be thrown. The optionally 'finally' block in called
in any event barring cutting power to the machine. The 'try catch finally'
blocks take the following form.


try { // block }   opt.[ catch ( Exception e ) ]   opt.[  finally { // block } ]

 

Rules Governing the Use of try catch and finally Blocks

There are a number of rules that describe the use of these exception
handling structures. First, for any try block there has to be at least
one catch or finally statement. (Even an empty try block insists on
having either a catch or finally statement.)


Example1 
try{

                    System.out.println("No exception possibility");
                    }
              finally{
                    System.out.println("Still need a catch or a finally statemenet");
                    }
 

In the usual case, the try block will contain a method that may lead to an
exception being thrown. In this case a catch statement must be provided.
The compiler will always tell you if this is the case.


Example 2
   try{
                    Thread.sleep( 1000 );
                      }
                   catch(InterruptedException ie){
                System.out.println("Need a catch statment if an exception may be thrown");
                     }


The third rule is that there can at most only one finally statement. There
can however be any number of catch statements.

A fourth rule may be described. Exception subclasses must be caught
before their more general parent classes. Both notions described in rule
three and four are captured in the following example.

Example 3     try{
                       Thread.sleep( 1000 );
                        }
                     catch(InterruptedException ie){
                        System.out.println("Need a catch statement if an exception may be thrown");
                        }
                     catch(Exception ie){
                       System.out.println("The more general exception must follow the subclass");
                       }
     // the compiler would not let this catch clause be placed before the one above it
             finally{
                      System.out.println("The compiler will only allow a single finally block");
                      }

The following example shows how the rest( ) method would be rewritten in order
to handle the exception thrown by sleep( ).

Example  public void rest( ){
                    try{
                          Thread.sleep(60000);
                          }
                          catch(InterruptedException ie){
                          System.out.println("Interrupted Exception");
                         }



Handling Multiple Exceptions



In the following code section of an imaginary method, a variety of
things can happen
which effects the control path taken.

Code sample

             //  ...
             // somewhere inside a method
             //...
       try{
             // exceptions waiting to happen
            }
       catch( SubException es){
         // say or do something
             }
       catch( AnotherException ea){
         // say or do something
             }
       catch( ParentException ep){
         // say or do something
             }
       finally{
         // code executed in any case
             }
             //  ...
            // the next line following the finally block of the method
            //  ...


No Exception Occurs

If no exception occurs, the code in the try block finishes
execution, the finally
block executes and execution resumes
at the line following the finally block.


A SubException Occurs

If a SubException is thrown, execution leaves the try block
at the point the exception
was raised and goes to the catch
block associated with SubException. After this code
is
executed, the finally block is executed and execution
proceeds at the line following
the finally block.


ParentException is Thrown

If a ParentException is thrown, execution exits the try
block and proceeds at the catch
block associated with
the ParentException. Once this block executes, the
finally block
executes and control proceeds at the line
following the finally block.


An Unknown Exception Occurs

If an unknown exception occurs, execution proceeds
directly to the finally block. When
the finally block is
finished executing, control leaves the method entirely.
This is an
uncaught exception which will next appear
in the caller.



Stack Tracing



The Exception Class

The Exception class has a couple constructor forms and several
useful methods which
can be used to augment the information
that is returned when an exception occurs.
For an example look
at the end of the assignment section.

  

 Constructors

public Exception( )

  Constructs an Exception with no specified detail message.

public Exception(String s)

  Constructs an Exception with the specified detail message.

 Methods inherited from Throwable                                              3 of 7 methods

 String 
 getMessage( ) 

 Returns the error message string of this throwable object.

 void 
 printStackTrace( ) 

 Prints this Throwable and its backtrace to the standard error stream.
// there are two more printStackTrace methods, one prints the stack 
// trace to a specified print steam and another prints to a PrintWriter

 String 
 toString( ) 

  Returns a short description of this throwable object.


Using printStackTrace( )


The printStackTrace( ) method is useful to unravel a set of events
that lead back to the location where the error occurred. Following is
some Java code that makes several nested calls that inevitably lead
to an exception being thrown. The printStackTrace( ) method is called
to trace through the call stack back to where the error occurred.
 

The Call Stack

Method calls are, at the machine level, directives to go to an address
and run the list of
instructions that are stored there. If from this
location a call is made to a nested method,
information about the first
method has to be stored somewhere while the computer is
busy
attending to the new block of information. The computer uses a data
structure
called a stack to store the details of where in a method's
instruction list execution is at,
before going off to execute the new
block of code. ( The following is a figurative
description of what goes
on inside the runtime environment at the machine level. )


Diagram of nested methods being called in a series

main( ) |
        | --getA( ) |
                      |
                      | --getB( ) |
                                     |
                                     |---getC( ) |
                                                    |
                                                    |   // exception thrown
 


The stack trace shows the path in reverse order of how it was traversed
to get to
the point where the exception was thrown . 

The following code sets up a nested set of methods that will end up
throwing an
exception. The printStackTrace method is used to show
the behavior that occurs
when an exception is thrown.
 

Example

public class Trace{
public static void main(String[]args){
    getA( );        
    // line 3 of main where a method calls the method that calls the bad method

    }
    static void getA( ){
       getB( );                     // line 6 call on method that calls the bad method
    }
   static void getB( ){
       getC( );                    // line 9 first call on bad method
    }
    static void getC( ){
     try{
        int i=1;
        int j=0;
        int k= i /j;                 // line 15 where the trouble starts
       }
       catch (ArithmeticException ae){
          ae.printStackTrace( );   // here is the printStackTrace( ) method being called
      }
   }
}

This code results in the following output to the command line. Notice
the stack trace reports from where the error occurred proceeding to
report as it works back up the calling stack finally to main.
 

Output of the printStackTrace( ) method

C:\NewCode>java Trace
 
java.lang.ArithmeticException: / by zero
        at Trace.getC(Trace.java:15)
        at Trace.getB(Trace.java:9)
        at Trace.getA(Trace.java:6)
        at Trace.main(Trace.java:3)

 

Using the getMessage( ) method

The getMessage( ) method is used to return the String message that
is passed into the Exception
constructor that is designed to receive
an error message.


Example
  public Exception(String s)  
// getMessage( ) returns String


For example a class can be built extending the Exception class,
building a constructor that
accepts a String object and then
invoking the appropriate parent constructor using a super
( )
constructor call.


Example 1   
class PowerDown extends Exception{

                             PowerDown ( String reason ){
                             super(reason);
                             }

                             PowerDown( ){ } // no args constructor
                         }


The new Exception class can then be used in different circumstances
and the
getMessage( ) method can return a variety of appropriately
related messages.


Example 2  
class Reactor {
                         static int temp;
                         public static void main(String[]args){
                             temp =(int)( Math.random( )*2400 ) ;
                           try {
                             if(temp>2000)
                                throw new PowerDown("temperature too high");
                            else if( temp< 200)
                                throw new PowerDown("temperature too low");
                               }
                           catch(PowerDown pd){
                              System.out.println(pd.getMessage( ));
                              }
                           }
                      }


Assertions 
   //   for reference, not on final 

There are implicit assumptions in most programs we write. Though
humans think
they are obvious, computers don't. An example, we
think of our ages as being only
positive numbers while computers
have no problem with a person being -3. We
assume that interest
rate at the bank is a positive value while charges are subtracted

from our accounts. We would not be comfortable with a negative
interest rate although
we might not mind negative charges being
subtracted from our account. What is
logically not feasible is possible
for the computer. A technique to test for different
assumptions we
make is called assertions.

An assertion is an assumption you believe to be true. Assertions
are used to help
assure quality control of software, so that it is as
bug free as possible. The following
examples are from Cay
Hoorstman's 'Computing Concepts with Java 2 Essentials'. It
has been supplemented with some real values and a main
method where it's methods are called.


Example Adapted from Cay Hoorstman's 'Computing Concepts
with Java 2 Essentials'
// supplemented with values and main( )

public class Assertion{
static double root=0;
    public static void check(boolean b){
     if (!b){
        System.out.println("Assertion failed");
        new Throwable( ).printStackTrace( );
        System.exit(1);
        }
     }
 

public void computeIntersection( ){
           
          double r=.5;
          double x=.1;
          double a=.001;
         // double y = r * r -( x - a ) * ( x - a );
          double y=-1;
      Assertion.check(y>=0);
          // the assertion check provides assurance y is not negative
            //  calling the square root on a negative number yields NaN
         root = Math.sqrt(y);
         }

public static void main(String[]args){
Assertion a=new Assertion();
a.computeIntersection( );
System.out.println("Root: " + root);
}
}

If an Exception is thrown by the assertion it will show up in the
stack trace.

 

The 'asserts' Keyword

To simplify and perhaps ensure uniform implementation Java has
added the 'asserts'
keyword to the JDK1.4 to do assertions. This
will have immediate impact on old
code compiled in JDK1.4 only
on code that was unlucky enough to have used the
'asserts' word
as an identifier. The compiler is supplying a transitional accommodation

where it will temporally allow asserts to co-exist as an identifier or
as a keyword.
Practically we can consider 'asserts' to be a keyword
from this point forward.

The 'asserts' keyword takes care of creating testing code and may
be left in code
after assertion testing as a protection against further
modifications that may result
in bugs. 

The following code is included just to emphasize that runtime
exceptions can be caught like other exceptions.


Example of a Runtime Exception Being Caught Using a try catch Block


class TroubleFix{
      public static void main(String[] args) {
        try{
           int x =1 / 0;
           System.out.println(x + " But x will never be printed!");
           }
         catch(RuntimeException re){
           System.out.println("\n " + "Error Description: " + "\"" + re.getMessage( ) + "\"");
           }
          
           System.out.println("Proceeding Like Nothing Happened!" + "\n ");
          }
}   


 


Self Test                                                  Self Test With Answers



1) Select the incorrect statement.

a) Checked exceptions arise in a correct program.
b) In a correct program, runtime exceptions  should never occur.
c) You are not expected to handle Error class objects.
d) Throwable are a subclass of the Checked Exception category


2) The following code will

  class Dv{
               public static void main(String[] args) {
                 System.out.println("Running Test");
                 int x =1 / 0;
                }
         }

a) not compile
b) compile but fail to run
c) compile and run and throw a runtime exception
d) compile and run successfully without error reports


3)  The sleep method throws InterruptedException.
     What will the following code do?

 class X2{
     public static void main(String args[]) throws InterruptedException {
         Thread.sleep(100);
         }
     }

a) does not compile
b) compiles but fails to run
c) compiles and runs and throws a runtime exception
d) compiles and runs successfully but may throw an exception
 

4) Which of the following statements regarding  exceptions is not correct?

a) there can only be one finally block
b) for every try block there must be either a catch or finally block
c) for every try and catch block there must also be a finally block
d) there can be any number of catch blocks
 


Exercise



Use the examples in the note to answer the following questions.

Q1.Write a class with no error protection that throws a divide by zero exception.
      // shows doing nothing

Q2.Write an exception class called Flat and throw it from an if clause
     with a boolean value,
NoAir. (Don't use try and catch in this question.
     This will require declaring main( ) as
throwing the exception.)
 
// shows throws being used

Q3 In a try clause throw Exception. In the corresponding catch clause
     catch the Exception
object.On catching it, print to screen "Exception
    caught", and from a finally block, print
to screen the word continuing.   
// demonstates try catch finally

Q5  Create an extension of Exception that uses the constructor of the
      Exception class that allows a string message to be provided. You
      will need to use super( ) to invoke the parent constructor to get this
      behaviour in your extension of the Exception class.
Then use the
      getMessage( ) method to extract this
string when the exception is
      thrown.

      ( If you have trouble with this question, don't fight it too long. A
       sample of code that illustrates this formulation is included at the
      end of the note. )
 
      // shows getMessage( ) in use 


Q5. Create a system of methods that nest an error. Use the
      printStackTrace method 
to trace the error through the call stack.     
         // shows printStackTrace( ) in use

 


Example

class MotorFailure extends Exception{
   MotorFailure(String cause){
   super(cause);
   }
}        // should really add the no-args constructor as well
         // now in case someone extends this class

// Now this exception class can be instantiated with the constructor
// that takes a descriptive
string. This string is returned if getMessage( )
// is called on the exception object thrown.

class MotorTest{
public static void main(String[]args){
 try {
       throw new MotorFailure("blown gasket");
      }
      catch(MotorFailure mf){
           System.out.println( mf.getMessage( ));
          }
    }
}