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: