3. "CATCHING" AN EXCEPTION (AND "TRY" BLOCKS)
The exceptions handlers provided with java do not provide for recovery, after having issued a
warning execution is abandoned. To instigate a recovery process the programmer must cause the method
in which the exception occurs to catch the exception. We do this by including a catch
block in our code. This has the form:
catch(ExceptionClass ec) {
.....
}
For example to "catch" an arithmetic exception of the form generated by the code presented in
Table 1:
catch(ArithmeticException error) {
.....
}
A catch block is only entered if a detetected exception is of the same type as its argument (which
must be some sub-class of the class Throwable). Note that an instance of the class
ArithmeticException is also an instance of the class RuntimeException,
Exception and so on (Figure 1).
Once we have caught an exception, one of the things we might like to do is output a warning the an
exception has been found. To do this we can make use of the methods defined in the class
Throwable. One of these is the toString method which returns a
short description of "this" throwable object. Thus we can write a catch block as follows:
catch(ArithmeticException error) {
System.out.println("\nOwn exception " + error.toString() + " caught");
}
To use a catch block we also requires something called a try block. This has the form:
try {
.....
}
and delimits the the part of a method from where it is possible to invoke the catch block. The
try block must immediately precede its associated catch block. Thus,
with respect to the code presented in Table 1 we might include the try block as follows:
try {
// Divide first by second and output result
System.out.println("Division = " + input1/input2);
}
Thus, given the code presented in Table 1, we can include a catch and try block as shown in Table
3. Some sample output in table 4 is presented in Table 4, note that we continue processing one the
exception has been cuaght (i.e. we recover) as evidanced by the END output.
// 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 {
// Input two integers
int input1 = new Integer(keyboardInput.readLine()).intValue();
int input2 = new Integer(keyboardInput.readLine()).intValue();
// Try block
try {
// Divide first by second and output result
System.out.println("Division = " + input1/input2);
}
// Catch block
catch(ArithmeticException error) {
System.out.println("\nOwn exception " + error.toString() + " caught");
}
// End
System.out.println("END");
}
}
|
Table 3:Catch and try block example
$ java OwnExceptionGeneratorApp
4
2
Division = 2
END
$ java OwnExceptionGeneratorApp
4
0
Own exception java.lang.ArithmeticException: / by zero caught
END
|
Table 4: Sample output
4. MULTIPLE CATCH BLOCKS
When writtiong our own exceptions handlers we are mot limitted to single catch blocks, we can
include as many as we like. For example in the code presented in Table 2 we can include a second
catch block to catch (say) an IOException. This will of course necitate a redefinition of the try
block. The code is presented in Table 5 together with some sample output in Table 6.
// 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 {
// Try block
try {
// Input two integers
int input1 = new Integer(keyboardInput.readLine()).intValue();
int 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");
}
// End
System.out.println("END");
}
}
|
Table 5:Multiple catch blocks
java OwnExceptionGeneratorApp
4
2
Division = 2
END
$ java OwnExceptionGeneratorApp
4
0
Own exception java.lang.ArithmeticException: / by zero caught
END
$ java OwnExceptionGeneratorApp
4
x
Own exception java.lang.NumberFormatException: x caught
END
|
Table 6: Sample output
As an alternative to the code presented in Table 5, we may define a single catch block whose
parameter is a super-class of all the exceptions we wish to catch amd include within the catch block
some code to identify the particular exception we have caught. To do this we can make use of the
instanceof operator. Thus:
catch(Exception error) {
if (error instanceof ArithmeticException) System.out.println("\nOwn arithmetic exception " +
error.toString() + " caught");
else {
if (error instanceof NumberFormatException) System.out.println("\nOwn number format exception " +
error.toString() + " caught");
else System.out.println("\nOwn other exception " + error.toString() + " caught");
}
}
Note: When working with multiple catch blocks make sure that the class type for each block
is not a super-class. If you need to use a super-calss make sure that it appears at the end of the
sequence!
5. CREATING YOUR OWN EXCEPTION CLASS
Given a particular application we may wish to create our own exception class, for example we might
wish to create an exception class NegativeNumberException which is a sub-class of
RuntimeException. If we look at the Throwable class this has two constructors
(Figure 1), one with no arguments and ome witn a string argument. If we use the first of these to
crearte an instancec of the Class Throwable:
Throwable myException = new throwable();
the statement:
System.out.println(myException.toString())
will cause the instance name myException to be output. If we use the second constructor,
for example:
Throwable myException = new throwable("Instance of Throwable");
the statement:
System.out.println(myException.toString())
will cause the output:
myException: Instance of Throwable
to be produced. The statement:
System.out.println(myException.getMessage())
will output Instance of Throwable (or null if no error message has been
supplied, i.e. when the default constructor is used).
If you examome the sub-classes of the class Throwable, most of them do not add any
further functionality other than redefining the constructors. Thus our desired
NegativeNumberException might be defined as follows:
class NegativeNumberException extends RuntimeException {
// --------------------- CONSTRUCTOS ---------------------
public NegativeNumberException() {
super();
}
public NegativeNumberException(String errorMessage) {
super(errorMessage);
}
}
To throw an exception we require a throws statement. This has the form:
throw < ExeptionObject >
and is usually coupled with a slection state ment of some form (if-else, case). Thus to throw an
instance of our NegativeNumberException might write:
throw new NegativeNumberException();
or:
throw new NegativeNumberException("Input must be a positive number");
The above is incoporated into some appropriate code as illustrated in Table 7 (example output in
Table 8). Note that the code includes a call to the printStackTrace method contained in the
Throwable class. This dispalys the names of the methods that are visited by the JVM in
search of an appropriate catch block.
// 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() {
super();
}
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 {
// Input two integers
int input1 = new Integer(keyboardInput.readLine()).intValue();
int input2 = new Integer(keyboardInput.readLine()).intValue();
// Try block
try {
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) {
error.printStackTrace();
}
// End
System.out.println("END");
}
}
|
Table 7:Own exception
$ java OwnExcepGenVer3App
4
2
Division = 2
END
$ java OwnExcepGenVer3App
0
2
NegativeNumberException: Input must be a positive number
END
$ java OwnExcepGenVer3App
4
0
NegativeNumberException: Input must be a positive number
END
|
Table 8: Sample output
Note: A throws clause lists the
exceptions that can be thrown by a method, for example:
public static void main(String[] args) throws IOException
This is not the same thing as a throws statment!