Catching Exceptions
Do you remember this code?
// This is the Hello program in Java
class Hello {
public static void main (String args[]) {
/* Now let's say hello */
System.out.print("Hello ");
System.out.println(args[0]);
}
}
Do you remember what happened when you ran the program without giving it any command line arguments? The runtime system generated an exception
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException at Hello.main(C:\javahtml\Hello.java:7)
What happened was that since we didn’t give Hello any command line arguments there wasn’t anything in args[0]
. Therefore Java kicked back this not too friendly error message about an “ArrayIndexOutOfBoundsException.”
Previously we fixed this problem by testing the length of the array before we tried to access its first element. This worked well in this simple case, but this is far from the only such potential problem. If you were to check for every possible error condition in each line of code, you would find your code becoming bloated with more error checking than actual code. Moreover you then have to start checking for errors in the error conditions. In older languages like C, Basic and Fortran you sooner or later you find yourself resorting to goto or longjmp or other such ingredients in the recipe for illegible Spaghetti Code
The goal of exception handling is to be able to define the regular flow of the program in part of the code without worrying about all the special cases. Then, in a separate block of code, you cover the exceptional cases. This produces more legible code since you don’t need to interrupt the flow of the algorithm to check and respond to every possible strange condition. The runtime environment is responsible for moving from the regular program flow to the exception handlers when an exceptional condition arises.
In practice what you do is write blocks of code that may generate exceptions inside try-catch blocks. You try the statements that generate the exceptions. Within your try block you are free to act as if nothing has or can go wrong. Then, within one or more catch blocks, you write the program logic that deals with all the special cases.
Here’s an example of exception handling in Java using the Hello World program above:
// This is the Hello program in Java
class ExceptionalHello {
public static void main (String args[]) {
/* Now let's say hello */
try {
System.out.println("Hello " + args[0]);
}
catch (Exception e) {
System.out.println("Hello whoever you are");
}
}
}
Some exceptions need to be caught and dealt with while others are generally considered to be so horrific that the runtime system, just gives up. The compiler will complain if you write code that doesn’t watch out for the not-too-dangerous exceptions, but you’ll need to watch out for the really dangerous ones (like ArrayIndexOutOfBoundsExceptions) yourself.
Sometimes catching an exception can feel like a little yippy dog that finally catches a car. Now that it’s got hold of the bumper between its teeth, what is it going to do with it? Many times there may not be much you can do. Bad exceptions stop the program by default. This is at least preferable to unhandled exceptions in most programming languages where the entire system can come crashing down around your feet with a core dump or worse. Sometimes you may want to this too. In that case you can call the System.exit(int)
method to halt your running program.
Other times you may just break out of a loop you were in and continue with the rest of your code. This is most common when an exception isn’t really unexpected or when it doesn’t badly affect your program logic.
You may or may not print an error message. If you write an exception handler and you don’t expect it to be called, then by all means put a
System.out.println("Error: " + e);
in your exception handler. That way if something does go wrong (and something always does) you’ll at least know where it went wrong. However don’t put an error message in exception handlers you expect to be exercised in the course of normal program flow. Remember, they’re exceptions, not errors.
In the next section we’ll see lots of examples of code that can possibly generate exceptions which must be caught. We’ll talk more about exceptions in a later chapter, but this is the bare bones you need to know to respond to the exceptions generated by the java.io classes we’ll be discussing in the next section.