– Dr. Who
Exceptions are errors that are generated while a computer program is running. Such errors are called run-time errors. These types of errors are different from the errors that the compiler generates (called compile-time errors).
Compile-time errors are generated in response to erroneous syntax in the source code. Run-time errors are generated in response to erroneous semantics. For example, it is not a compile-time error to divide by zero, but it is a run-time error.
13.1 Generating your first exception
Suppose you want to divide two numbers. If you cause the computer to divide by zero, an exception will be thrown at run-time:
p u b l i c c l a s s ExceptionExample { p u b l i c s t a t i c v o i d main(String args[]) { System.out.println( "f(0)=" + f(0)); } p u b l i c s t a t i c i n t f(i n t x) { r e t u r n 1/x; } }
This generates the following run-time error:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionExample.f(ExceptionExample.java) at ExceptionExample.main(ExceptionExample.java)
13.2 Intercepting the Run-time Error
We intercept the error before it occurs. This is called guarding the input. For example, we could say:
p u b l i c s t a t i c i n t f(i n t x) { i f (x == 0) r e t u r n 0;
r e t u r n 1/x;
}
But this would return an invalid answer for a bad input (which is actually much worse than stopping the program and informing the user). To intercept an exception, after it has been thrown, you use a try-catch block:
p u b l i c c l a s s ExceptionExample { p u b l i c s t a t i c v o i d main(String args[]) { t r y { System.out.println( "f(0)=" + f(0)); } c a t c h (ArithmeticException e) {
System.out.println("Bad input for f!"); } System.out.println("program continues..."); } p u b l i c s t a t i c i n t f(i n t x) { r e t u r n 1/x; } } This outputs:
Bad input for f! program continues...
We see that the program does not stop suddenly, when dividing by zero. When a run-time error occurs, according to the Java Language Specification [Gosling], the Java machine will throw an exception. When an exception is thrown, a non-local transfer of control occurs from the area that generated the exception to a place that can catch the exception. In our case, we caught the exception, emitted an error
message, and then allowed the program to continue. The interesting part about this approach is that we can select where the error handling occurs, and protect the program from bombing during a mission-critical area of the code.
13.3 Defining your own Exception
Suppose you are interested in building a credit card processing routine. You want the routine to perform an elementary check on the credit card number, and if there is a problem, it throws an exception. When our check finds a problem, a new
exception is thrown called a CreditCardException. Here is how we define it:
p u b l i c c l a s s CreditCardException e x t e n d s Exception { p u b l i c CreditCardException(String s) { s u p e r (s); } p u b l i c s t a t i c v o i d check(i n t i) t h r o w s CreditCardException { i f (i < 0) { t h r o w n e w CreditCardException(
"credit card ="+i); }
} }
The Exception class is defined in the java.lang package. A new exception may be defined by sub-classing the Exception class. The class that does the credit card check only checks to make sure that the credit card is positive. However, this is an implementation detail, and a more complete credit card check could easily be performed. Here is a class that checks the credit card:
p u b l i c c l a s s CheckCreditCard { p u b l i c s t a t i c v o i d main(String args[]) { t r y { CreditCardException.check(-9); } c a t c h (CreditCardException e) { e.printStackTrace();
System.out.println("Heres the cc exception");
r e t u r n ;
}
System.out.println("done."); }
13.4 Checked and Unchecked Exceptions
There are two kinds of exceptions, checked and unchecked. When a method is invoked that throws a checked exception, then the invoking method must place the invocation in a try-catch block, or declare it in the throws clause. For example:
p u b l i c s t a t i c v o i d check(int i) {
CreditCardException.check(-9); }
Causes a compile-time error:
Error : Exception CreditCardException must be caught, or it must be declared in the throws clause of this
method.
ExceptionExample.java line 41 CreditCardException.check(-9);
Thus, we have two possible actions, declare the CreditCardException in the throws clause:
p u b l i c s t a t i c v o i d check(i n t i) t h r o w s CreditCardException {
CreditCardException.check(-9); }
Or we can place the invocation inside a try-catch block:
p u b l i c s t a t i c v o i d check(i n t i) { t r y { CreditCardException.check(-9); } c a t c h (CreditCardException e) { e.printStackTrace(); } }
The checked is defined by sub-classing the Exception class. The unchecked exception is defined by sub-classing the RuntimeException class. With an unchecked exception, No try-catch construct is needed to invoke methods or
statements that throw RuntimeExceptions. For example, dividing by zero can throw a RuntimeException.
Figure 13.4-1 shows the java.lang Exception subclass hierarchy.
java.lang.Throwable java.lang.Exception java.lang.ClassNotFoundException java.lang.CloneNotSupportedException java.lang.IllegalAccessException java.lang.InstantiationException java.lang.InterruptedException java.lang.NoSuchMethodException java.lang.RuntimeException
Figure 13.4-1. An overview of the java.lang exception classes
A zoom in of the java.lang.RuntimeException class hierarchy is shown in Figure 13.4-2. java.lang.Exception java.lang.RuntimeException java.lang.ArithmeticException java.lang.ArrayStoreException java.lang.ClassCastException java.lang.IllegalArgumentException java.lang.IllegalMonitorStateException java.lang.IndexOutOfBoundsException java.lang.NegativeArraySizeException java.lang.NullPointerException java.lang.SecurityException
13.5 The MBNF for the t r y statement
The Modified Backus Naur Form (MBNF) for the try-catch block is:
tryStatement
"try" statement
< "catch" "(" parameter ")" statement > [ "finally" statement] .
It is typical to use the try-catch block with any code that might fail. As seen with the division example, given above, there was no requirement for the try-catch block. Thus, there was no requirement that the code be able to handle run-time errors locally.
A typical pattern for the try-catch block follows:
t r y { . . . } c a t c h ( . . . ) { . . . } c a t c h ( . . . ) { . . . } . . . For example: t r y {
// create an instance of your applet class
a = (Applet) Class.forName(className).newInstance(); } c a t c h (ClassNotFoundException e) { System.out.println( "ClassNotFoundException in AppletFrame"); r e t u r n ; } c a t c h (InstantiationException e) { System.out.println( "InstantiationException in AppletFrame"); r e t u r n ; } c a t c h (IllegalAccessException e) { System.out.println( "IllegalAccessException in AppletFrame"); r e t u r n ; }
When an exception is caught, a message is obtainable as an instance of a string, using:
e.getMessage()
A sophisticated program might log the messages from the exceptions (called error logging) so that proper steps can be taken to correct the error.
At the other extreme, we could catch the exceptions and then continue running, ignoring all exceptions. For example:
t r y {
out.write(buffer);
} c a t c h (Exception e) { }
A new exception is defined by extending the Exception class. For example:
c l a s s FileFormatException e x t e n d s Exception {
p u b l i c FileFormatException(String s) { s u p e r (s);
}
Try catch blocks can slow down the execution of code slightly. They create a local scope of variables. It is therefore important to place exceptions at the right level of granularity. It would not be appropriate to, for example, place every division inside of a try-catch block. It would be better practice to program by assertion. Programming by assertion protects the input to a method so that it is reasonable and unlikely to cause an exception.
The checked exception decends from the Exception class. Such exceptions do require a try-catch statement, or are required to be in methods that throw a checked exception. For example:
p u b l i c c l a s s ThrowsExample {
p u b l i c s t a t i c v o i d main(String args[]) {
Float value = Float.valueOf("1.0"); System.out.println(value);
value = Float.valueOf("blah blah blah"); System.out.println(value);
} }
Will output:
1.0
_exceptionOccurred: java.lang.NumberFormatException (blah blah blah)
java.lang.NumberFormatException: blah blah blah at java.lang.Float.valueOf(Float.java) at ThrowsExample.main(TrivialApplication.java) at com.apple.mrj.JManager.JMStaticMethodDispatcher.run(JMA WTContextImpl.java) at java.lang.Thread.run(Thread.java)
The java.lang.NumberFormatException is an unchecked or RuntimeException, sine the NumberFormatException subclasses the IllegalArgumentException, which subclasses the RuntimeException.
With checked exceptions, the try-catch block is required. For example:
p u b l i c c l a s s FileExample { p u b l i c s t a t i c F i l e openFile() { r e t u r n n e w File("foo.txt"); } p u b l i c s t a t i c FileReader openFileReader() { r e t u r n n e w FileReader(openFile()); } p u b l i c s t a t i c v o i d main(String args[]) { System.out.println(openFileReader()); } }
Will not compile. The syntax error is:
Error : Exception java.io.FileNotFoundException must be caught, or it must be declared in the throws clause of this method.
TrivialApplication.java line 23 return new FileReader(openFile());
The following shows a way to fix the code:
p u b l i c c l a s s FileExample { p u b l i c s t a t i c File openFile() { r e t u r n n e w File("foo.txt"); } p u b l i c s t a t i c FileReader openFileReader() t h r o w s FileNotFoundException {
r e t u r n n e w FileReader(openFile()); } p u b l i c s t a t i c v o i d main(String args[]) { t r y { System.out.println(openFileReader()); } c a t c h (FileNotFoundException e) { e.printStackTrace(); } } } In summary,
1. An exception is a run-time condition.
2. Exceptions can be thrown by any instance of a class that subclasses java.lang.Throwable.
3. Exceptions must be caught in order to be intercepted and processed. 4. A try-catch block can be used to process exceptions
5. The finally clause is always executed.
6. Checked exceptions subclass the Exception class.
7. Unchecked exceptions subclass the RuntimeException class.
13.6 Exercises
1. A Master card number is a positive integer that has 16 digits. Design a credit card checking routine that throws a CreditCardException when the number of digits in the credit card is invalid.
2. Write a program that computes how much it costs to leave a computer on 24 hours a day, 7 days a week. Assume that the computer uses 0.2 KW/Hr and that power costs 10 cents per KW-Hr. Tabulate the costs of operating a computer as a function of the cost of power. In crease the cost of power by 5 cents per Kw-Hr until you get to 50 cents per Kw-Hr. Use a function to perform the computation. Make the cost of power and total amount of power consumed parameters. If the
parameters are negative, throw an InvalidPowerException. Make this a RuntimeException so that try-catch blocks are not required.