10. Java Exceptions

What is an Exception?

  • When a problem occurs, Java attempts to transfer control to a method that can deal with the problem, called exception handlers. An exception handler can either correct the problem (fault handlers), gracefully terminate the program (trap handlers), or simply ignore the problem. However, if there is no exception handler and an exception occurs, then the appropriate error messages are displayed and the program is terminated.

Types of Problems: errors and exceptions.

  • Exceptions can be further divided into I/O exceptions and runtime exceptions:
  • I/O exceptions occur when bad things happen to an otherwise good program, such as trying to open a file that doesn't exist.
  • Runtime exceptions are programming errors, such as a bad cast, an out-of-bounds array access, or a null pointer access.
  • Errors are system errors, such as memory exhaustion. Programmers should not attempt to handle these.

Throwable is the superclass for all exceptions & errors.

The Exception and Error classes are organized in a hierarchy of subclasses.

For example:

  • java.lang.Exception class has as one of its subclasses java.lang.RuntimeException
  • java.lang.RuntimeException class has as one of its subclasses java.lang.IndexOutOfBoundsException
  • java.lang.IndexOutOfBoundsException class has as one of its subclasses java.lang.ArrayIndexOutOfBoundsException

This allows the program to catch the specific ArrayIndexOutOfBoundsException, and/or any of its superclasses IndexOutOfBoundsException, RuntimeException or Exception. The more general the exception (higher in the hierarchy), the more subclass exceptions could be caught, but handling them properly would require more work.

Catching an Exception

  • To handle an exception explicitly or implicitly thrown by a method, the method call must be called inside a try block. The handler code is placed in an immediately following try block in a catch clause.
  • Syntax for try block:
try {
  // statements monitored for exceptions
}
catch( exception-class obj-reference ){
  // statements that handle exception
}
/* There may be more than one catch clause if more than one exception is caught */
  • NOTE: An exception does NOT need to be caught in the method that triggers the exception. In fact, it's often better to catch and handle the exception in one of the calling methods (further down the call stack).
  • Suggestion: Include inside the try block (after the code that may throw an exception) the statements to be executed IF there is NO exception! This eliminates the need to check after the catch clauses if it worked or not.

Example:

//be sure to import java.util.* for ArrayList
ArrayList<String> list = new ArrayList<String>();
String str;  int i; boolean errorOccurred;
// other code may be here
do {
          errorOccurred = false;
          try{
                    // code here to assign to i
                    str=list.get(i);// might throw an exception
                    // put code here for when there's NO exception
          }
          catch(IndexOutOfBoundsException exp){ 
                    errorOccurred=true;
                    System.err.println("Exception: " + exp);
                    // should do more to "handle" the exception here
          } // end catch exception
}while( errorOccurred);
  • In the above example, if the IndexOutOfBoundsException is thrown from ANY method inside the try block, a reference to the exception object will be passed to exp and execution will transfer to the block with the catch clause.
    • NOTE: You do not have to match every type of exception that is thrown (implicitly or explicitly) in the try block with a catch clause. Include a catch clause for the exception(s) you want to handle for this try block.

Another Exception Example and "finally"

  • You may catch a specific exception and more than one exception, but the more specific exceptions MUST be put before the more general exceptions, for example
// This is inside some method
int intCh;
char ch;
try {
          System.out.println("Enter a character: ");
          intCh = System.in.read(); // may throw IOException
          ch = (char) intCh;
          .
          .
          .
}// end try
catch( IOException ex ){// may be other statements here
          System.err.println(ex); // calls toString on ex
} // end catch IOException
catch( Exception ex ){
          System.err.println(ex);
} // end catch Exception

finally clause:

  • A finally clause is executed whether or not an exception is thrown
  • A finally clause is executed even if there's a return statement before it
  • A finally clause is used when we must guarantee the some cleanup code is executed
  • A finally clause follows any catch clauses and has the syntax:

finally {

// cleanup statements

}

  • A finally clause is optional if you have at least one catch clause, but required if you don't have any catch clauses at the end of a try block
  • Example (after the ArrayList try block on the previous page):

finally { str = null; list = null; }

When to Catch an Exception

  • You MUST catch an exception (i.e., call the method in a try block and include a catch clause for the exception) if you call a method defined with the throws clause, for example

public abstract int read() throws IOException { . . .}

unless your method also is defined with the throws clause for the same exception(s) that the called method throws (more on throws clause on the next page)

  • You SHOULD catch an exception if an exception may occur in your program (for example, an ArrayIndexOutOfBoundsException)
/*
Exercise 10.1 - Determine which exception will be thrown by the Scanner class' nextInt or nextDouble methods.  
Change a previously written Java program that reads numeric input from the user.  
Call the input method in a try block and catch the specific exception that the input method would throw 
if the user entered non-numeric input. Allow the user to input the number again if an exception is caught. 
Suggestion: DON'T use recursion, but put the try block and catch clause inside a loop, using a boolean variable that will be tested in the loop condition.
 */
import java.util.Scanner;
import java.util.InputMismatchException;
public class Exercise_10_1_Exception
{

static Scanner oScanner = new Scanner(System.in);

private int i_Total = 0;


public boolean inputMethod()

{

boolean isError = false;

try // Comments: Score deduction - should put try catch inside loop

{

for(int i = 0; i < 5; i++)

{

System.out.println("Enter integer number to sum");

i_Total = i_Total + oScanner.nextInt();

}

}

catch(InputMismatchException ex)

{

isError = true;

i_Total = 0;

}

return isError;

}


public static void main( String[] args )

{

Exercise_10_1_Exception oException = new Exercise_10_1_Exception();

// Catch java.util.InputMismatchException for oScanner.nextint()

boolean isException = oException.inputMethod();

if(!isException)

System.out.println("Total = " + oException.i_Total);

else

System.out.println("Exception: Invalid integer");

} // end main

} // end class Exercise_10_1_Exception

Throwing Exceptions

  • When should your program throw an exception? There are many methods in which bad input or invalid parameter values are impossible to handle (for example, in a constructor). In these cases, it's best to have these methods/constructors throw an exception.
  • Define your method with the throws clause, which is given after the right-parenthesis of the parameter list and has the syntax: throwsexception-list

for example,

public void someMethod( int i )
      throws IOException, MyException{
. . . 
} 
// MyException is a subclass of Exception that you write
  • Inside the method that throws the exception(s), when an error occurs (usually detected with an if statement), create an instance of an exception (passing an argument which describes the exception) and pass it in the throw statement, which has the syntax:

throw(exObj);

if( myExceptOccurred ){
     MyException ex = 
              new MyException("MyException Occurred");
     throw( ex );
}
  • Throwing an exception causes control to return immediately to the calling method, which either handles the exception or implicitly throws the exception to its calling method.

NOTE ABOUT WHERE TO THROW AND CATCH EXCEPTIONS: The reason for throwing an exception is to allow another method handle the exception, different from the method where the error occurred. Therefore, it's a bad idea to throw an exception and include a corresponding catch clause in the same method as the throw statement. If you want to handle an error inside the same method, just use if-else statements.

Exception Exercises

/*
Exercise 10.2: 

Change any class from a previous exercise or programming homework assignment to throw an exception

if the input or parameter is out of range. Write a driver application program that catches that exception,

but continues (after handling the exception, may loop). Make sure the catch clause is not in the same method

as the throw statement.

 */
// Note: Modified exercise 2.4 to get cube using square function (Not a good example but just to demonstrate concept)
import java.io.*;
import java.util.Scanner;
public class Exercise_10_2_ThrowException
{

static Scanner oScanner = new Scanner(System.in);

public static void main(String[] args)

{

int i_num;

int i_cube;


for(int i = 0; i < 5; i++)

{

System.out.println("Enter number to get cube (-500 to 500 range)");

i_num = oScanner.nextInt();

i_cube = getCube(i_num);

if(i_cube == -1000)

System.out.println("Error in getCube(), continue with next number.");

}


System.out.println("Main Ends");

}


public static int getCube(int i)

{

int i_cube = 0;

try

{

i_cube = i * getSquare(i);

System.out.println("Cube: " + i_cube);

}

catch(IOException e)

{

System.err.println("Error: " + e);

i_cube = -1000; // sample indicator

}

return i_cube;

}


public static int getSquare(int i) throws IOException

{

IOException oIOException = new IOException("Number is out of range");

if(i >= -500 && i <= 500)

return i * i;

else

throw(oIOException);

}

}

Class Hierarchy of Exceptions and Errors

class java.lang.Throwable (implements java.io.Serializable) 
      class java.lang.Error
             class java.lang.LinkageError
                     class java.lang.ClassCircularityError
                     class java.lang.ClassFormatError
                          class java.lang.UnsupportedClassVersionError
                     class java.lang.ExceptionInInitializerError
                     class java.lang.IncompatibleClassChangeError
                          class java.lang.AbstractMethodError
                          class java.lang.IllegalAccessError
                          class java.lang.InstantiationError
                          class java.lang.NoSuchFieldError
                          class java.lang.NoSuchMethodError
                     class java.lang.NoClassDefFoundError
                     class java.lang.UnsatisfiedLinkError
                     class java.lang.VerifyError
             class java.lang.ThreadDeath
             class java.lang.VirtualMachineError
                     class java.lang.InternalError
                     class java.lang.OutOfMemoryError
                     class java.lang.StackOverflowError
                     class java.lang.UnknownError
             class java.awt.AWTError
      class java.lang.Exception
             class java.lang.ClassNotFoundException
             class java.lang.CloneNotSupportedException
             class java.lang.IllegalAccessException
             class java.lang.InstantiationException
             class java.lang.InterruptedException
             class java.lang.NoSuchFieldException
             class java.lang.NoSuchMethodException
             class java.lang.RuntimeException
                     class java.lang.ArithmeticException
                     class java.lang.ArrayStoreException
                     class java.lang.ClassCastException
                     class java.lang.IllegalArgumentException
                          class java.lang.IllegalThreadStateException
                          class java.lang.NumberFormatException
                     class java.lang.IllegalMonitorStateException
                     class java.lang.IllegalStateException
                          class java.awt.IllegalComponentStateException
                     class java.lang.IndexOutOfBoundsException
                          class java.lang.ArrayIndexOutOfBoundsException
                          class java.lang.StringIndexOutOfBoundsException
                     class java.lang.NegativeArraySizeException
                     class java.lang.NullPointerException
                     class java.lang.SecurityException
                     class java.lang.UnsupportedOperationException
            class java.awt.AWTException
            class java.io.IOException
                     class java.io.CharConversionException
                     class java.io.EOFException
                     class java.io.FileNotFoundException
                     class java.io.InterruptedIOException
                     class java.io.ObjectStreamException
                          class java.io.InvalidClassException
                          class java.io.InvalidObjectException
                          class java.io.NotActiveException
                          class java.io.NotSerializableException
                          class java.io.OptionalDataException
                          class java.io.StreamCorruptedException
                          class java.io.WriteAbortedException
                     class java.io.SyncFailedException
                     class java.io.UnsupportedEncodingException
class java.io.UTFDataFormatException

Exception Handling Example Program

  • This program tries to convert a String from a JTextField into an int. If it fails, an exception is caught and handled in this program. Note that if the [Enter] key is pressed while the cursor is in a JTextField (or TextField), an ActionEvent occurs.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ExceptionHandlingExample extends JFrame
                         implements ActionListener{
      private String str;
      private JTextField tf1, tf2;
      private int sum=0;
      public ExceptionHandlingExample(){
            super("Exception Handling Example");
            setLayout(new FlowLayout());
            str = ""; 
            tf1= new JTextField(10);
            tf1.addActionListener(this);  
            tf1.setVisible(true);
            tf1.setEditable(true);// default
            tf2=new JTextField(30);
            tf2.setEditable(false);
            
            add(new JLabel("Enter a number and press [Enter] "));
            add(tf1);
            add(tf2);
      } // end constructor
      public void actionPerformed(ActionEvent e){
            int inputInt=0;
            try {
                  inputInt = Integer.parseInt(tf1.getText());
                  sum += inputInt;
                  tf2.setText("Sum is now "+ sum);
            } // end try
            catch( NumberFormatException nfe ){
                  JOptionPane.showMessageDialog(null, "Must enter digits only!",
                        "Input Error",    JOptionPane.ERROR_MESSAGE);
            } // end catch 
            tf1.setText("");
      }
      public static void main( String[] args ){
            ExceptionHandlingExample fp =new ExceptionHandlingExample();
            fp.setSize(400, 200);
            fp.setVisible(true);
            fp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      } // end main
} // end class ExceptionHandlingExample

Exception Throwing Example

  • The following program computes and displays sqrt3(x) for x = 16 and x = -16. In the second case, the attempt to compute sqrt3(-16) throws a custom "negative number" exception, which is handled by the caller of the caller (jumps 2 methods). Here, we defined our own exception class (isn't necessary, this is just an example of creating your own Exception class):
import java.io.*;
public class NegativeNumberException extends IOException{
public NegativeNumberException(double irritant){
     super("non-negative number expected, not " 
                   + irritant);
}
public NegativeNumberException(){
      super("non-negative number expected");
}
} // end NegativeNumberException class
// in a separate file:
public class ExceptionDemo{
public static double squareRoot(double x)
                                            throws NegativeNumberException{
System.out.println("Entering squareRoot()");
if (x < 0){
      NegativeNumberException exp
         = new NegativeNumberException(x);
      throw(exp);
}
System.out.println("Exiting squareRoot()");
return Math.sqrt(x);
}
public static double cubeOfSquareRoot(double x)
                                                      throws NegativeNumberException{
System.out.println("Entering cubeOfSquareRoot()");
double temp =
          squareRoot(x); // may implicitly throw exception here
System.out.println("Exiting cubeOfSquareRoot()");
return temp * temp * temp;
}
public static void displayCubeOfSquareRoot(double x)
{
double result = 0;
System.out.println(
              "Entering displayCubeOfSquareRoot()");
try{
      result = cubeOfSquareRoot(x);
      System.out.println("result = " + result);
 }catch(NegativeNumberException e){
      System.err.println("Error: " + e);
      // more steps here?
}
System.out.println(
              "Exiting displayCubeOfSquareRoot()");
}
public static void main(String[] args){
System.out.println("Entering main()");
System.out.println(
              "calling displayCubeOfSquareRoot(16)");
displayCubeOfSquareRoot(16);
System.out.println
              ("calling displayCubeOfSquareRoot(-16)");
displayCubeOfSquareRoot(-16); // trouble
System.out.println("Exiting main()");
} // end main
} // ExceptionDemo
  • for example: