Next: Throwing exceptions. Up: Exceptions. Previous: What is an exception?.


Catching exceptions

Java has a way of writing a program that can catch an exception, via what's called a try block. A try block looks vaguely like an if...else statement.

import csbsju.cs160.*;

public class Example {
    public static void main(String[] args) {
        IO.print("Number of scores? ");
        int num_scores = IO.readInt();
        IO.println("Type 'em.");
        int total = 0;
        for(int i = 0; i < num_scores; i++) {
            total += IO.readInt();
        }
        try {
            IO.println("Average: " + (total / num_scores));
        } catch(ArithmeticException e) {
            IO.println("Error: Can't average over zero scores");
        }
        IO.println("Good-bye");
    }
}
Here, we've told the JVM to print the quotient of total and num_scores. We've placed it in a try block of braces, and followed it up with a catch expression. Inside the parentheses after catch, we've indicated that we specifically want to catch an ArithmeticException, and between the braces, we've told the computer what to do in the case that, in the process of completing the code within the try block, an ArithmeticException is raised.

When the computer reaches a try block, it executes all the code within the block, in sequence. If no exception is raised while performing the code, the computer skips over the catch block and does the code afterward.

Number of scores? 2
Type 'em.
3
5
Average: 4
Good-bye

If, however, an exception is raised during the try block, the computer immediately skips to the catch block and see whether the exception matches the exception named in the parentheses. If so, it performs the code given in the following braces and then performs the code afterward.

Number of scores? 0
Type 'em.
Error: Can't average over zero scores
Good-bye
In this example, the computer never executes the for loop body, since i immediately reaches its destination of num_scores. It gets into the try block and tries to divide total by num_scores, which results in division by 0. The JVM raises an ArithmeticException, and so the computer immediately skips over the rest of the try block to check out the catch clause. In this case, the raised exception matches the exception named in the clause, so the computer does the code within the catch clause and finally does whatever follows the clause.

This example is a bit contrived. A better (i.e., more readable) technique would be to avoid the exception in the first place, rather than try to catch it after it occurs.

if(num_scores != 0) {
    IO.println("Average: " + (total / num_scores));
} else {
    IO.println("Error: Can't average over zero scores");
}

Getting exception information

The catch clause actually has a parameter variable, named within the parentheses, with which one can access information about the raised exception. Above, I called this parameter variable e. This is an object like any other, and it will have a few methods. (But I can actually call it anything I want.)

For example, all exception objects contain a method called getMessage(), which returns a String holding additional information about the exception.

try {
    IO.println("Average: " + (total / num_scores));
} catch(ArithmeticException except) {
    IO.println("Error in averaging: " + except.getMessage());
}

Exception objects could conceivably carry additional data about the offending information. Generally, they only carry a string describing the problem, however.

Checked and unchecked exceptions

Sometimes, the Java compiler will insist that you catch a particular type of exception. These are called unchecked exceptions because Java will not insist that they be checked. The exceptions we've mentioned so far have all been unchecked.

One example of a method that throws a checked exception is Thread.sleep(), which will halt for a number of milliseconds specified as a parameter.

Thread.sleep(20); // won't compile: exception not caught
This method can throw an InterruptedException, indicating that the method wasn't able to sleep as long as requested because of some other signal it received. Java will refuse to compile any code that calls Thread.sleep() but doesn't specifically handle this exception.

So what you must do is place the code that uses Thread.sleep() within a try clause, followed by a catch clause to handle an InterruptedException.

try {
    Thread.sleep(20);
} catch(InterruptedException e) { }
Notice that here, we've told Java to do nothing when the exception occurs - essentially, we just want to ignore the exception. For this particular exception, this is frequently the best thing you can do.

(In fact, we used Clock.sleep() in Labs 2 and 4, defined in the csbsju.cs160 package. We did this instead of using the Thread class in the java.lang package because doing that instead would force us to worry about this checked exception, and we hadn't studied exceptions yet.)


Next: Throwing exceptions. Up: Exceptions. Previous: What is an exception?.