Chapter 11

Throwing and Catching Exceptions in Java

Perhaps the most important aspect of writing a complete and useful Java program is dealing with exceptions to its intended execution. To paraphrase an old piece of wisdom, a program runs well for just one reason, but it can fail for all sorts of reasons. Writing a solid program has to do with good design and focusing on correct results. Protecting a program from failure has to do with checking every operation that could go sideways and providing a remedy. I’ll discuss how the exception system works in the Java language and the tools at your disposal to implement it.

In this chapter, we’ll cover the following topics:

  • Understanding the role exceptions play
  • Using a try-catch block
  • Understanding exception types
  • Calling methods that throw exceptions
  • Recognizing common exception types

Understanding the Role Exceptions Play

Let’s start with a simple premise: Any program can fail for just about any reason. Some reasons you might introduce yourself, such as code that depends on conditions you can’t enforce. For example, if you make an assumption about the size of an array you can’t directly control, your program runs the risk of counting on array elements that don’t exist, as shown in Listing 11-1.

Listing 11-1: Java program that generates an exception

 void main(String args[]) {
for (int i = 0; i < 3; i++)
         System.out.println(args[i]);
   }

$ java BadArrayCall 1 2
1
2
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
        at BadArrayCall.main(arrayexc.java:4)

The for loop in the ArrayException program assumes that the args array will have at least three elements in it. The compiler cannot possibly check for this condition because the length of the args array isn’t set until a user executes the program. The way to fix it is plain. Until then, however, the JVM has to throw an exception to indicate the problem.

Other kinds of exceptions are harder to fathom at first. They may relate to conditions you can’t control or simply don’t understand the first time you see them. You might have program code to open a file that no longer exists; there is a java.io.FileNotFoundException class to cover that eventuality. What is less obvious is which classes throw it and when. (Here’s a hint: The File class doesn’t use it at all.)

Still other exceptions are so completely removed from your own environment that all you can do is wonder what they mean. If you’ve used several web applications that are Java-based, chances are you’ve seen one or two long stack traces dumped in your browser, suggesting something went wrong on the server. You can’t do anything about these at all.

Exceptions can and do occur all the time, even in solid program code. You can remove some exceptions by correcting the code, but eradicating them altogether isn’t a viable option. Any program that draws on system resources, local and remote filesystems, networks, and other outside services have to acknowledge those requests sometimes fail. There is only one remedy for that: Embrace failure and incorporate it into your code.

Understanding Exceptions

certobjective.eps

Exceptions make up the second most prolific type system in the Java core libraries following the supertype java.lang.Object. It begins with the class java.lang.Throwable, which extends Object and implements the java.io.Serializable interface. The Serializable interface lets the JVM convert implementing classes to a stream of bytes that, unlike the toString() method, will retain elements of the class’s structure.

As you can see in Figure 11-1, two key classes extend the Throwable class: Error and Exception. In the section “Understanding Exception Types,” I’ll discuss the purpose of these two classes in detail.

Figure 11-1: Throwable class relationships

c11f001.eps

The JVM throws only objects that inherit from the Throwable class.

The idea of a Throwable object is a novel one. Once a Java program encounters a problem that disrupts its normal flow of execution, the JVM captures certain information about the program state and creates an object to hold it. The JVM then throws this object, as in outside the execution path. If there is nothing in the program to catch it, the JVM receives it back, prints some of this information, and terminates the program run.

The Throwable class itself is concrete but doesn’t have many practical direct uses. As a parent to both the Exception and Error classes, it provides a method interface and a default implementation for each method. A diagram of its key constructors and methods is shown in Figure 11-2. A UML class diagram supplies one compartment for all operations. A strictly-correct diagram would not separate methods and constructors, which I have added solely for visual appeal.

Figure 11-2: A diagram of the Throwable class

c11f002.eps

The key data that a Throwable object holds is a stack trace, a list of methods that were open and waiting on called methods to return when the exception was thrown. The more methods that are open at the time, the deeper the stack. Listing 11-2 shows a program that produces a deeper stack.

Listing 11-2: A program that throws a stack trace

final class StackedThrow {
public void callOne(String bits[]) {
      callTwo(bits);
   }
public void callTwo(String bits[]) {
      callThree(bits);
   }
public void callThree(String bits[]) {
      System.out.println(bits[0]);
   }
public static void main(String args[]) {
      StackedThrow st = new StackedThrow();
st.callOne(args);
   }
}
$ java StackedThrow
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at StackedThrow.callThree(arrayexc.java:18)
        at StackedThrow.callTwo(arrayexc.java:14)
        at StackedThrow.callOne(arrayexc.java:10)
        at StackedThrow.main(arrayexc.java:23)

Stack traces are written in inverted form. The method that began the trace appears at the bottom; the last method appears at the top. I’ve named the methods in Listing 11-2 to highlight this scheme.

You wouldn’t expect to see a trace this simple in working code because they’re easy to repair. The traces you will see tend to be much harder to untangle. They involve calls from one class to another across different packages written by other programmers and often result from some misunderstanding that winds through several methods before causing a problem.

A Throwable object might also contain a message, in the form of a String object, that describes the exception’s cause. These are nice to have when you get them, especially if they help isolate the source of the problem. If the problem isn’t caused by buggy code or by a failure to acquire a system resource, chances are it’s a parameter with a bad value. If an exception message can tell you where it’s best to start looking, it can save a lot of time.

Handling Exceptions

An exception seems like a surprising thing when you encounter it, and surprising is a nasty word in programming. Even if your programs don’t behave as you’d like, they should fail in predictable and expected ways to the same degree they produce correct and reliable results. In Java, that responsibility means handling the exceptions that come your way.

What Java does with its exception type system, first and foremost, is identify and name well-known errors in program code execution. If you refer to the API of any package in the core libraries, you’ll see Exception subclasses (and possibly Error subclasses too) listed as part of the package’s contents.


All unchecked exceptions extend the RuntimeException class, which itself subclasses the Exception class.

For the sake of discussion, I’ll refer to code that can throw exceptions as risky code. The term risky code does not include incorrect code, such as attempts to read past the length of an array or cast a value to a type to which it doesn’t conform. Bugs of this sort are called unchecked exceptions, which is a dry but diplomatic term meaning “something you did in your code the JVM can’t do much to prevent.” The ArrayIndexOutOfBoundsException class is one example.

Checked exceptions represent a class of conditions that fall outside of your program’s normal flow of control, as I described earlier. It is nonetheless a necessary part of programming in any language to understand that programs never operate in a foolproof environment. Networks, for one, are notoriously failure-prone resources. They may fail only momentarily and recover very quickly, but sooner or later your program code will encounter one those failures. Checked exceptions ensure that you’ll be able to identify that failure; the exception facility in Java gives you a way to acknowledge and address those failures if and when they occur.

As a practical matter, the distinction between these types can be reduced to this: The compiler makes you deal with checked exceptions when they appear in code. It doesn’t make you deal with unchecked exceptions. That’s how the term checking originates in all of this.

When exceptions do get thrown, the ideal robust program will respond with the following goals in mind:

Save the data or program state. There may be no effective way to store the current results of a program or even indicate what progress was made. Indeed, to realize this first goal, you must plan for failure and devise a strategy to minimize the loss of information. It seems a lot of people don’t like thinking about how their code fails while they’re trying to figure out how to succeed, but it’s not optional. Software that is worth the money its programmers were paid will account for the reasonable and predictable paths it can take. That’s all there is to it.
Inform the user. In the best of all worlds, a program user restarts after a crash and everything Just Works. That’s a great feature in software we all use, but it sure doesn’t happen by itself. A program user has to know where to find the results and whether they are reliable for use in a subsequent session. Information to the user should always consider whether they have the knowledge and experience to interpret the message. If you’ve handled buggy code before, you know most software doesn’t do this well.
Recover and continue execution. I like saying that for software to succeed, it has to be resilient to error. Of course, I am dead wrong about that. Successful software only has to raise its users’ tolerance for failure above its capacity for failure. Still, I want programmers to write resilient programs. Let others think about gaming the user. Writing code that recovers from exceptions and continues past them—and in the best of worlds, makes them transparent to the user—isn’t very hard to do, but it can get awkward and cumbersome.

To achieve some or all of these goals, a programmer must act on two fronts. One, eliminate any unchecked exceptions that can occur. This work isn’t always easy or self-evident. It helps to know a few key Exception classes ahead of time. I’ll address that part later in this chapter, in the section “Recognizing Common Exception Types.”

Two, catch any checked exceptions that are thrown by the code. In a way, this work can be a little easier because the compiler will complain when you haven’t done it. The work can also be tedious, especially if you let the compiler lead you around by the nose, pointing out each checked exception you haven’t addressed. I discuss how to do this work in the next section.

Using a try-catch Block

certobjective.eps

Java’s catching mechanism is composed of three blocks, a try block, one or more catch blocks, and a finally block. You can put any legal statements in the try block, but it’s expected that one more of those statements could throw an exception. A catch block can name one or more exception classes like parameters. Here’s a trivial example:

public void tryCode() {
   System.out.println(“Outside try block”);
try {
      System.out.println(“Inside try block”);
int x = 5;
   }
catch (Exception ex) {
      ex.printStackTrace();
   }
// Won't compile
   System.out.println(x);
}

The tryCode() method contains a try block that prints a message, then declares and initializes the integer x. The catch block declares it will receive an Exception object, which like any other type, also supports any subclasses. If an exception is thrown, the variable ex refers to the object.


The least useful catch block, by a wide margin, is an empty one.

In this example, I call the printStackTrace() method using this reference. Although it appears in Java code all the time, it is about the least useful way to handle an exception. All it does is dump the stack trace, just like the JVM. The program doesn’t terminate on the spot; that’s the only difference.

You should also note that a try block has its own scope within the method. Any variable, like x, that is declared inside a try block is lost once the block completes. Such variables do not carry over to the catch block. They are also not visible to the whole method unless they are declared at method scope.

Catching an Exception

To catch an actual exception, you must include at least one statement in the try block that throws. The section “Calling Methods That Throw Exceptions” later in this chapter has more detail on this point. For now, I’ll provide example code to show how the mechanism works. Let’s say we want a program that hangs around for 5 seconds before it quits. The Thread class has a sleep() method that takes a number of milliseconds for an argument. You might be tempted to write it like this:

final class Sleeper {
public static void main(String args[]) {
      Thread.sleep(5000);
   }
}

This code, however, will not compile. If you try, you’ll get this error:

Sleeper.java:3: error: unreported exception InterruptedException; 
   must be caught or declared to be thrown
                Thread.sleep(5000);
                            ^
1 error

The compiler complains that you haven’t handled the InterruptedException class, which means it’s required when calling the Thread.sleep() method. I’ll rewrite the class accordingly:

final class Sleeper {
public static void main(String args[]) {
try {
         System.out.println("Entering sleep()");
         Thread.sleep(5000);
         System.out.println("Exited sleep()");
      }
catch (InterruptedException iex) {
         System.out.println("Sleeper.main: " + iex);
      }
   }
}
$ java Sleeper
Entering sleep()
<five second pause>
Exited sleep()

I’ve added methods in the try block to print before and after calling the sleep() method. I’ve also changed the catch block to print the name of the current class and invoke the InterruptedException object’s toString() method. This program doesn’t induce the exception it catches, which may make the try/catch block seem unnecessary to the untrained eye. Nonetheless, the compiler requires us to observe every exception thrown by any method we call.

Throwing an Exception

But what’s the point of implementing a catch block if you can’t see how it works? Fortunately that’s not a hard problem to solve. Remember that exceptions are just classes, so you can create one if you have access to its constructor. The JVM can throw any object that is a subclass of the Throwable class; as it turns out, so can you.

Replace the code in the body of the try block in the current example with this statement:

throw new InterruptedException("Thrown by hand");

If you run the program now, you’ll see this output:

Sleeper.main: java.lang.InterruptedException: Thrown by hand

See Chapter 3, “Using Java Operators and Conditional Logic,” for a review of decision constructs.

If instead you insert a throw statement before the other statements, the compiler will complain that the other statements are unreachable. This error occurs because throwing an exception is a transfer of control, similar to what takes place with a return statement, except control transfers directly to a catch block, as shown in Figure 11-3. Any subsequent statements in the try block are ignored.

Figure 11-3: Throwing an exception in a try block

c11f003.eps

The compiler can’t evaluate which statement in a try block will raise an exception at runtime. It knows which methods could throw an exception—that is what checked exceptions are for. A throw statement, however, leaves no room for doubt. As with a return statement, no statement that follows in the code block may execute. The compiler is required to complain and insist the matter be corrected before it can compile the offending class.

The compiler also complains if you declare a catch block with an exception that cannot be thrown in the try block. You’ll see this error if you remove both the Thread.sleep() method call and the throw statement. The Exception class itself is not subject to this rule; even with an empty try block, you can declare catching an Exception object and it will compile..

Using Multiple Catch Blocks

There’s one more aspect to consider with a thrown exception. The JVM will transfer control to the first catch block that matches the exception’s type.

The statements in one try block can throw more than one kind of exception. When that’s the case, you can write separate catch statements to handle each one. Because the JVM matches the exception by type, catch blocks that define the narrowest range of exceptions must come first. Supertype exceptions must come later, as shown in Figure 11-4.

Notice in Figure 11-4 that the two unrelated exceptions, InterruptedException and FileNotFoundException, could be listed in either order, so long as the first type doesn’t claim exception objects of the second type. If you place a more general type first, the compiler tells you that exceptions of the narrower types are already caught, as shown in Listing 11-3.

Figure 11-4: A try block with multiple catch statements

c11f004.eps

Listing 11-3: Program with catch blocks listed out of order

// needed for FileNotFoundException reference
import java.io.*;
final class BadCatch {
public static void main(String args[]) {
try {
         System.out.println("Whichever");
         Thread.sleep(5000);
         FileInputStream fd = new FileInputStream("/tmp/dummy");
      }
catch (InterruptedException iex) {
         System.out.println("BadCatch.main: " + iex);
      }
catch (Exception ex) {}
catch (FileNotFoundException fnfex) {
         System.out.println("BadCatch.main: " + fnfex);
      }
   }
}
$ javac BadCatch.java
arrayexc.java:13: error: exception FileNotFoundException has 
   already been caught
      catch (FileNotFoundException fnfex) {
      ^
1 error

In this arrangement, the catch block for Exception receives control for any exception thrown that isn’t an InterruptedException object. Any subsequent catch blocks are unreachable code.

There’s another unfortunate outcome in this example. One of the catch blocks has no code. I purposely did this to save space on the page and avoid distracting you from the main point—but this outcome is quite common with catch blocks. It’s easy to dismiss them as unimportant code in the moment and tell yourself you’ll return to it later.

Resist this urge. If you don’t intend to think through all the consequences of running your code, you don’t intend to write a complete program (also my excuse here). It’s as simple as that. Remember the goals:

  • Save data or program state.
  • Inform the user.
  • Provide ongoing execution.

Don’t worry too much about it, though. You’ll fall short of these goals, even when they’re not hard to implement. Every programmer does. It’s often a question of the time available to complete a program. Sometimes, the awkward style that exception code foists on the programmer is discouraging. The extra indentation takes up space; long class names for exceptions make that problem worse. Coding multiple catch blocks can be repetitive and error prone. Writing tests to cover every catch block without modifying the try block is also a tedious exercise.


Inspecting others’ programs is called code review. It’s not just an exercise in proofreading; it’s also a valuable learning tool.

This work can take on a life of its own that, under time pressure, doesn’t seem justified by the time required to do it well. In this matter, I can only say your conscience is your guide. It wouldn’t hurt, though, to collaborate with other programmers and establish some incentives. I know one company that uses a catch jar; if someone spots an empty or trivial catch block you wrote, you have to put some money in the jar (and fix the block).

Fortunately, the Java SE 7 platform has added a couple of features to make writing exception code a little easier. One of those features is multi-catch statement syntax. It lets you declare multiple exception types for a single catch block so they can use the same code. I can now revise the current example like this:

catch (FileNotFoundException | InterruptedException mx) {
   System.out.println("BadCatch.main: " + mx);
}

Proper syntax requires you to separate exception classes from each other with a pipe and use a single variable to represent them. Now it’s possible to write one catch block for all exceptions that can use the same logic.

Using a finally Block

Let’s say you have a try block with several statements in it, which altogether can throw any one of several exceptions. You decide to write a catch block for each possible exception. One hard thing to sort out in this situation is how to get all the possible execution paths to transfer control to one place. In my example, there are three ways to leave the try block:

  • Normal execution.
  • Throw an InterruptionException object.
  • Throw a FileNotFoundException object.

And there are four possible paths that can follow from them:

  • Bypass all catch blocks.
  • Catch an InterruptedException object.
  • Catch a FileNotFoundException object.
  • Catch an Exception object.

The compiler will always let you catch an Exception object as a guard against bad logic.

When a catch block executes, it has two possible paths. It can execute normally, after which control bypasses the remaining blocks and processing continues in the host method. Or the catch block could also throw an exception. It’s just more Java code, after all, and just as vulnerable to bad logic (or a deliberate use of the throw statement) as any other code block. When a catch block throws an exception, however, there’s not a lot you can do to manage that new Throwable thing that isn’t awkward and cumbersome.

If you want to ensure that all possible paths of execution will transfer control to a single point, add a finally block to the end of your try-catch block scheme. A finally block is guaranteed to execute following any path of execution that results from a try-catch sequence, except when the JVM terminates the program or a call to the System.exit() method occurs along the way. Those two cases aside, it doesn’t matter if your code happens to cascade through a series of thrown exceptions: The JVM will return control, sooner or later, to the finally block.

A common use for the finally block is to release or close out system resources that were allocated along the way. Classes in the java.io and java.net packages do a lot of this. When you open files or network sockets, or even launch external processes (using the Runtime.getRuntime().exec() method), you acquire resources through the operating system that are bound to your program.

If a Java program dies “the right way,” most operating systems will figure out what happened and restore such resources back to their own pools. It is an egregious error to rely on that behavior taking place, however, and it’s as sincere a request for creating trouble for the system as a program can make. If you open a network socket or other system resource, you’re obliged to close it. The API will absolutely provide a method for that purpose. The same goes for any system resource you request.

At the same time, resources external to your program that you have allocated can fail for lots of reasons you don’t control. That’s where a finally block’s guarantee makes its money. If for some reason those conditions force your JVM to throw an exception, the finally block is your chance to release those resources before your program goes away. Listing 11-4 shows an example program that creates a test file (which it has to clean up) and tries a couple of remote network services.

Listing 11-4: Using a finally block to restore system state

import java.io.File;
import java.net.Socket;
import java.io.IOException;
import java.net.UnknownHostException;
final class TestResources {
private File file;
private Socket socket;
void getFile(String fname) {
try {
file = new File("newData");
if (file.createNewFile()) {
            System.out.println("New file");
         } else {
            System.out.println("Existing file");
         }
      } catch (IOException iox) {
         System.err.println("Problem getting file " + fname);
// could encounter the same IO problem
file = new File("test");
      } finally {
// clean up test file
         if (file != null) {
             file.deleteOnExit();
         }
      }
   }
void getConnected(String host, int port) {
try {
socket = new Socket(host, port);
      } catch (UnknownHostException ex) {
         System.err.println("No service at " + host + ":" + port);
      } catch (IOException ex) {
         System.err.println("Connection attempt failed");
      } finally {
         System.err.println("Closing down");
try {
if (socket != null) {
socket.close();
            }
            System.out.println("Socket resource closed");
         } catch (IOException ex) {
            System.err.println("Oh well, I tried.");
         }
      }
   }
public static void main(String args[]) {
      TestResources tr = new TestResources();
// does this file exist?
tr.getFile("plugh");
// test various sites and ports
tr.getConnected("localhost", 80);
// bad host
tr.getConnected("plugh", 1234);
// bad port
tr.getConnected("localhost", 99999);
   }
}
$ java TestResources
New file
Connection attempt failed
Socket resource closed
Closing down
No service at plugh:1234
Closing down
Socket resource closed
Socket resource closed
Closing down
Exception in thread "main" java.lang.IllegalArgumentException: 
      port out of range:99999
   at java.net.InetSocketAddress.<init>(InetSocketAddress.java:118)
   at java.net.Socket.<init>(Socket.java:189)
   at TestResources.getConnected(TestResources.java:33)
   at TestResources.main(TestResources.java:60)

The first thing you might notice is that exception handling can add a lot of lines of code. Here I’ve implemented the blocks in a straightforward way. The more deliberate your style, the bulkier it gets, but it’s too soon to discuss ways to tone it down. Get accustomed to the “added weight” for now. Somewhere lower on your list of things to learn, you can add “find a cleaner way to implement try blocks.”

Following the main() method, you’ll notice I create a TestResources object, exercising the getFile() method once and the getConnected() method three times. In the first case, the finally block in the getFile() method makes sure the test file gets deleted; that’s just good manners.

In the latter case, I am testing for success and failure of both checked and unchecked exceptions. Your results might vary. If you have a service open at port 80 of your own system, for example, the first connection attempt might succeed. The second one will fail, unless you happen to locate a system named plugh on your local network that’s running a service on port 1234. The third attempt will always fail: The highest-numbered port on a system is 65535.

Notice the finally block in the getConnected() method includes another try/catch block! That’s legal, of course, and necessary if you invoke a risky call inside. And it gets a bit crowded in the file too. There’s nothing to be done for that except to find a style that helps you manage the clutter without making the code harder to read. Again, worry about that later.

At last, you can see that my final test raises an unchecked exception. Spurious inputs like that are the kind of thing you can throw right back at the user if it doesn’t make sense to do anything else. There’s no reason to believe most programs are obliged to protect users against their own bad input—if in fact it’s coming from the user. There might instead be a configuration file in the mix, and for that situation, it would be nice if the program reported that the file’s content must be wrong.

If you just want to make sure some concluding bit of logic runs for all cases after your try/catch scheme, a finally block is the way to go. Simply add one at the end of any catch blocks you have.

The full set, in the abstract, looks like this:

try {
// risky code
}
catch (Exception ex) { 
// save data, inform the user
}
finally { 
// complete the logic
   // release allocated resources
}

Handling Unchecked Exceptions

So far I have carefully avoided using unchecked exceptions in my examples. It’s actually quite easy to illustrate the flow of execution to a catch block with clearly bugged code, as shown in Listing 11-5.

Listing 11-5: Catching an ArrayIndexOutOfBoundsException

final class CatchArraySize {
public static void main(String args[]) {
try {
for (int i = 0; i < 3; i++)
            System.out.println("" + args[i]);
         }
catch(ArrayIndexOutOfBoundsException arrx) {
         System.err.println("Array access exceeded length");
      }
   }
}
$ java CatchArraySize
Array access exceeded length

In one sense, the problem in the code has been solved. If the user inputs too few arguments, this program preserves its running state and informs the user. There is no data to save or an alternate path of execution to consider, but these things wouldn’t be hard to support.

We haven’t improved on what the JVM already does in this case, but this is a tiny piece of code. You could argue, with some force, that managing program errors this way in a very large body of code meets the basic criteria for exception handling and, in fact, allows you to customize it however you’d like.

On the other hand, catching exceptions you didn’t have to throw is a hard practice to justify. It leads to more lines of code, for one. It’s arguable that it improves at all on the JVM’s default output. It only defers the termination of a program in a trivial way. Perhaps most important, it hides the opportunity for replacing it with better code and it’s expensive to compute. To construct an exception object, you have to convert the stack track data to string form. The more data there is, the more expensive the object.


See Chapter 5, “Using Loops in Java Code,” for a refresher on the enhanced for loop.

For this example, you have already seen a solution in the language that helps you avoid it: the enhanced for loop. By rewriting this program with it, the problem we had drops out altogether, as shown in Listing 11-6.

Listing 11-6: Using an enhanced for loop for a variable argument count

final class PrintAnyArray {
   public static void main(String args[]) {
         for (String arg : args)
            System.out.println(arg);
   }
}
$ java PrintAnyArray
$ java PrintAnyArray 1 2
1
2
$ java PrintAnyArray a b r x v
a
b
r
x
v

Now the program reads the value of args.length itself and applies it automatically. We also could have used the args.length value as a limit in a basic for loop, which was the first approach in Java for averting an array bounds exception.

If there’s something worse than handling an ArrayIndexOutOfBoundsException in a catch block, it’s handling all unchecked exceptions using the Exception class. You’ll see a lot of code that does it. I, for one, discourage the practice. The first thing catching an Exception object tells me is that the programmer has developed some lazy habits. Or what’s worse, that they encountered an exception type that was strange to them, didn’t track it down, and used a catch block to defer the problem.

Even if that kind of code doesn’t break as I am maintaining or testing it, I’ll wonder when it might break. It’s a lot like having to be wary of a pit in a construction lot that has a thin plank over it. That’s energy spent on my own safety I’d much rather devote to the task at hand.

You will find more than a few examples on the Internet that use runtime exceptions to inform a try/catch example. Many of them provide a disclaimer, too: Just for illustration. When does that disclaimer ever work? Don’t develop this habit. Use exception handling when you can’t avoid it.

Understanding Exception Types

certobjective.eps

You now have enough example code and friendly advice to feel your way through exception handling. In this part of the chapter, I explore further the difference between checked and unchecked exceptions. I’ll also discuss the Error class and its descendants. Frankly, they get a bad rap, and even though you may not incorporate them into your code very often, they deserve a fair hearing.

Refer again to Figure 11-1. The Throwable class is the base of the exception system and represents the first object type the JVM knows how to throw. It is also a Serializable type, which means the JVM knows how to convert it into a byte stream.

Serializing an object is not the same as turning some aspect of it into a String value. Serializing translates a whole object into a form that retains the properties of its type. From this form, an object can be de-serialized and immediately used as an object again. When you want to share an object with another Java program or save it in its most complete object state, serializing gives you a way to do it.

However, the Serializable interface isn’t a good example of Java interfaces as you’ve learned them. For starters, it has no methods. As source code, it looks like this:

package java.io;
interface Serializable { }

Another interface, java.io.Externalizable, lets the programmer define how an object should be converted to a byte stream form and back.

This is called a marker interface by some and a tagging interface by others. Programmers use it to indicate to the JVM which types are suitable for storing and retrieving from a persistent form. What the JVM does to serialize an object isn’t a secret, but it’s meant to be a hands-off operation.

You’ll have no need to serialize exceptions in this chapter.

Understanding Errors

There are two kinds of Throwable objects a program should not catch, according to the JDK documentation. Both kinds are called unchecked exceptions. Classes that inherit from the Error class are one kind. They represent abnormal conditions in a program that, like checked exceptions, fall outside the direct control of a program.

Unlike checked exceptions, however, unchecked exceptions are by nature difficult to manage. The problems they identify often compromise the health of the JVM itself, which may call into question the sanity of the code it is running. Thus the documentation describes Error subclasses as Throwable objects a “reasonable program” would not catch.

Here are some examples of Error subclasses:

  • CoderMalfunctionError
  • IOError
  • LinkageError
  • VirtualMachineError

A CoderMalfunctionError occurs when a subclass of either the CharsetEncoder or CharSetEncoder abstract class encounters a problem encoding or decoding a stream of bytes. The IOError encapsulates “serious” I/O errors; that’s all the API documentation tells us. A LinkageError is a case in which one class has a dependency on another—for example, as a field member—but the second class has been changed and recompiled in a way that breaks the dependency.

The most descriptive of these types, from a program perspective, is a VirtualMachineError, which is a parent class to the InternalError, OutOfMemoryError, StackOverflowError, and UnknownError classes. The class names here form a descriptive picture of the problems they cover. Chances are you will rarely see these errors raised. The class documentation helps to see that such problems have nonetheless been named, categorized, and described.

Understanding Unchecked Exceptions

The other kind of unchecked exception inherits from the RuntimeException class, as shown in Figure 11-5. It can be thrown at any time, without warning, by a method or constructor. It occurs because of some disagreeable runtime event.

Many of these types, like ArrayIndexOutOfBoundsException, are conditions that arise from improper use of a language feature or operation. All arrays are subclasses of Object, for example, but their operations are built into the language. When one of those operations arrives at an insensible condition, the JVM communicates the problem by creating an exception object and sending it along.

Figure 11-5: Checked and unchecked exceptions by class type

c11f005.eps

Up to this point, I have defined unchecked exceptions as problems you can and should correct in your code. To be honest, that’s a white lie some instructors tell to motivate Java programmers. We want to make sure you focus on writing correct code before it becomes apparent that you can mask program problems with exception handling.

Some unchecked exception types, however, view JVM or system configuration as a source of invalid input. Unfortunately for beginners, these problems often appear as you’re experimenting with code and seem surprising. It then takes some time to understand the problem and more time to fix it correctly.

When you’ve gone through that a couple of times, it’s easier to understand why there are so many blocks that catch the Exception class: It covers every exception you haven’t specifically called out as well as every exception you’d rather not hear about. But just because the temptation can be strong doesn’t mean the practice is okay. These are still problems you should correct rather than handle silently.

Many classes fall in this category:

  • NegativeArraySizeException
  • IllegalArgumentException
  • SecurityException
  • UnsupportedOperationException

We’ve seen the NegativeArraySizeException class before; the JVM raises this exception any time you construct an array with a negative value. The IllegalArgumentException is the parent class to a broad category of bad arguments, including ones that have been fed to an object at the wrong time (IllegalThreadStateException). The JVM raises a NumberFormatException object when a String object that is supposed to have a numeric value can’t be converted.

SecurityException objects probably inspire a great deal of try/catch workarounds. It’s not usually obvious from the error messages they generate what to do to fix them. They are thrown by the java.lang.SecurityManager class for several reasons. Most of them concern requests for resources or operations the program does not have the privileges to use or invoke. Although it’s not an exam objective, you’ll save time and your sanity by reviewing the SecurityManager class and learning the formats of the files it uses.

The UnsupportedOperationException class is another self-evident type with a number of subclasses. You may encounter it early (and often) when you learn to use collection classes. It so happens that some collection classes don’t implement all the methods they should, according to the interfaces they have declared. Ugly as that is, it’s apparently an unavoidable condition. To compensate for this, the classes will throw UnsupportedOperationException objects to alert the programmer. It’s a learn-as-you-go kind of thing. On the bright side, it’s yet another good reason to depend on your JDK classes only after you’ve verified them with testing.

This branch of classes also covers cases such as trying to write to a read-only file system or trying to invoke a GUI on a system that doesn’t have a local monitor. Figure 11-6 shows this class and its direct subclasses.

Figure 11-6: The UnsupportedOperationException class and its direct subclasses

c11f006.eps

These are all conditions you don’t want to catch in code. It’s better to let a program fail, know the system isn’t configured to expectations, and fix these problems where they stand.

Understanding Checked Exceptions

The Exception class documentation defines checked exceptions as “conditions that a reasonable application might want to catch.” That’s not too exacting a formula. I take it to mean the distinction between checked and unchecked exceptions is, in some way, open to interpretation. I have to form my impression of the difference, more or less, by examples in the JDK core libraries.

Fortunately the practical definition is much easier to apply. As Figure 11-5 shows, checked exceptions extend the Exception class but not the RuntimeException class. And, as I said earlier, the JVM can throw an unchecked exception without warning. You the programmer, however, will not only throw and catch checked exceptions. To play the exception game properly, you’ll declare them as well.

Here’s the thing: Checked exceptions aren’t bad. They’re good. You want to throw them to callers. Why? Because they give you a separate way to communicate with your callers when something’s wrong.

Let’s take two examples, one with a constructor and one with a method. Listing 11-7 shows the familiar Customer class. In this version, its constructor accepts a String parameter. The constructor tries to match the parameter to an internal array of names. If it doesn’t, the name variable retains its initial empty value.

Listing 11-7: The Customer class with a constructor and a method

final class Customer {
// will be replaced by database access some day
private String[] names = { "Jess", "Guy", "Samuh" };
private String name = "";
public Customer(String str) {
for (String name : names)
if (name.equals(str)) this.name = name;
   }
public String getName() {
return this.name;
   }
public static void main(String args[]) {
      Customer cst = new Customer("Samuh");
      System.out.println(cst.getName());
cst = new Customer("Lance");
      System.out.println(cst.getName());
   }
}
$ java Customer
Samuh

$ 

The program output shows the problem. The code defends against a null value for the name member. There isn’t, however, such a thing as a default customer. If you start using a database later on, how can you tell the caller they’ve provided a name that has no match in the system?

You could encapsulate the constructor and use a method to return a NullCustomer subclass, like this:

private Customer(String name) {
// Validation now perfomed by getCustomer()
this.name = name;
}
public static Customer getCustomer(String str) {
for (String name : names) {
if (name.equals(str)) return new Customer(name);
   }
return new NullCustomer();
}

This approach has an elegance I admire. Callers receive an object, as they’d expect from a constructor. The caller now has to check whether the received object is useful, but it keeps communication to one channel. That can be a good thing, especially if the idea of null objects is applied consistently.


Chapter 9, “Inheriting Code and Data in Java,” discusses the obligations you assume when allowing inheritance in a class.

To implement this approach, however, you have to allow inheritance. If you do, there are other obligations a caller may reasonably infer you have also observed. It’s easy to remove the final keyword from the class declaration, but the practical consequences go beyond skating past the compiler.

If that prospect sounds like more work than benefit, let your constructor instead declare that it throws an exception. Create a class, such as CustomerNotFoundException. Let it extend the Exception class. Override any methods as you please, but often a good class name can cover the work you need. Then alter your constructor like this:

public Customer(String str) throws CustomerNotFoundException {
for (String name : names) {
if (name.equals(str)) this.name = name;
   }
   throw new CustomerNotFoundException();

}

The constructor’s signature uses the keyword throws to notify callers of the CustomerNotFoundException class. The exception can then be passed to the caller wherever the throw keyword is used in the constructor body. This structure is the calling card of a checked exception. It’s the same for a method:

public static Customer getCustomer(String str) throws 
      CustomerNotFoundException {
for (String name : names) {
if (name.equals(str)) return new Customer(name);
   }
   throw new CustomerNotFoundException();
}

A method or constructor can declare as many different exceptions as it needs to throw. Just separate the types with a comma the same way you would if you were implementing multiple interfaces.

The compiler will verify that a constructor or method throws the exception types that it declares. In these examples, the connection is obvious, but it isn’t always so plain. In the next sections, you’ll see how a method or constructor can also declare an exception that was thrown at it.

Calling Methods That Throw Exceptions

certobjective.eps

Now you see what declared exceptions are for. They make it possible to notify callers that some responses are thrown rather than returned. The cause of those exception responses may occur within the called method, but they can also be the result of a method or constructor the called method uses to perform its own computation.

It is assumed that these responses result from a condition the called method can’t (or shouldn’t) resolve on its own. Here again is where the practice of applying exception handling well relies as much on interpretation as following set rules.

When you call a method that throws checked exceptions, you have two options. One, the calling method can handle the exception with a try/catch block. Two, you can make the calling method declare the same exception. Some people call this the catch or declare requirement.

Catching a Checked Exception

Early in this chapter I used the term risky code. I had in mind specifically methods that throw checked exceptions. The risk is clear and specific, and it’s often a momentary problem. If you call a method that connects you to a remote server, any number of things can go wrong. The name you give for the server may be misspelled. Your system’s connection to the Internet may go down for a minute. A network device between you and the remote system may have to reboot. The remote system itself might be down.

A good checked exception class bundles the details in a way you, the calling programmer, can easily identify. You can then decide how to manage the exception when you receive it.

The rest you have already heard: Work to save data or state, inform the user, and provide a means to keep the program running. Admittedly, these goals are easier said than done. Let’s say you wanted to retry connecting to a remote server. The attempt will be futile if the server name is wrong (java.net.UnknownHostException) or the remote system stays down for a long time (java.net.ConnectException) or even something else (java.io.IOException). Listing 11-8 offers an incomplete example of this problem.

Listing 11-8: NetProblems class with multiple possible exceptions

import java.net.*;
import java.io.*;
final class NetProblems {
public static void main(String args[]) {
        Socket sock;
try {
sock = new Socket(args[0], 25);
        }
catch(UnknownHostException uhx) {
            System.out.println("Bad host name: bailing out");
        }
catch(IOException iox) {
            System.out.println("Network problem: bailing out");
        }
        System.out.println("Finished");
    }
}
$ java NetProblems
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at NetProblems.main(test.java:8)
$ java NetProblems foo.bar
Bad host name: bailing out
Finished
$ java NetProblems 192.168.15.108
Finished
$ java NetProblems localhost
Finished
$ java NetProblems 192.168.15.245
Network problem: bailing out
Finished

You also cannot use multi-catch syntax with a parent exception and any of its subclasses.

In the NetProblems class, I try to create a Socket object by connecting with a remote system’s email service. The well-known port for an email server that uses the Simple Mail Transfer Protocol (SMTP) is 25. I have implemented a catch block for each exception thrown by the Socket constructor I am using. The UnknownHostException class inherits from the IOException class, so they must appear in the order shown. I then try various command-line arguments with the class.

The program could inform the user more plainly when no argument is given. I’ve omitted that part for brevity. Notice when a clearly bad name is given, the code raises an UnknownHostException object. The IP addressing ending in 108 is another computer on my home network. The argument localhost is the system I ran the code on. The IP address ending in 245 does not exist. The output line Finished just shows that control transfers to the end of the try/catch block.

In each case I have only replaced the JVM’s standard complaint formula with a simpler message. That’s a start, albeit a shallow one. If you’re going to write more resilient code, there’s plenty of work ahead. The idea isn’t to quit on it, however, if you’re short on time. Rather, find a package that already handles this work and employ it. Just because you want resilient code doesn’t mean you have to write it yourself.

Declaring a Checked Exception

Assuming it is better to pass along an exception rather than handle it, you can declare it as part of your method or constructor signature. There are some rules you have to observe because exceptions are classes, some of which are parents to others. As you’ve already seen, parent exceptions must be listed after child exceptions under a single try block. You also cannot use multi-catch syntax with two or more inheritance-related exceptions.

When you declare an exception received from a method or constructor you call, you can throw instead a parent exception. In the best case, this flexibility lets you capture a multitude of declared exceptions with a shorter declaration, thereby avoiding some clutter.

In the worst case, you may be tempted to declare throwing the Exception class itself. Think about this for a second. Although you can avoid throwing exceptions with a little extra work, such as making default or null versions of your return type, sometimes throwing is the right thing to do. Even so, few programmers will thank you for the extra work.

Declaring a more general exception type, however, almost always makes it less clear why you’re throwing exceptions in the first place, other than to defer a legion of problems. If you think tracking a class’s hierarchy back to the Object class can get tedious, wait until you have to track an exception through its method calls the same way. It’s a frustrating exercise in navigation.

You cannot declare a more specific exception or break a general type down into subclasses. There’s no reason to believe you should be able to, but it’s a tempting thought once you’ve worked with exceptions for a while.

Recognizing Common Exception Types

certobjective.eps

Several exception classes come up time and again in code, either while you’re learning or because the missteps they represent are pretty common. At this point, you’ve got the resources and the skills you need to review these classes by documentation and experiment with them.

Before you consider taking Oracle’s OCA exam, you should also write as many of your own test cases as you can. It’s a goal of the exam to ensure that you can read Java code effectively. That said, you’ll never read code as carefully before you’ve written code that just won’t compile as after. You’re going to find out that, in the beginning at least, you need to learn the elements of the Java language one by one before you can build true confidence in reading large tracts of code accurately.

There isn’t a place in most books of this sort to say, “Good luck to you!” So here it is: Study carefully. Don’t rely completely on any one source, including this book! Write, break, and repair plenty of Java code, and you’ll learn enough to move on.

I’ve sprinkled common exception types you should know in examples throughout the book as well as this chapter. I reprint them here for the sake of a one-stop list:

  • ArithemticException
  • ArrayIndexOutOfBoundsException
  • ClassCastException
  • IOException
  • NullPointerException
  • NumberFormatException
  • SecurityException
  • UnsupportedOperationException

The Essentials and Beyond
This chapter covered the theory and application of exceptions and exception handling in Java code. Exceptions make up an entire type system, beginning with the Throwable class. Each subclass names an error and supplies information, in the form of a stack trace, about its occurrence.
There are two broad classes of exceptions: checked exceptions, which are declared, verified by the compiler, and raised by the JVM as conditions warrant; and unchecked exceptions, which specify errors in the code. Although you can use them the same way you’d use checked exceptions, declaring one is tantamount to saying there’s something wrong with your code you would rather not fix. Unchecked exceptions are descendants of the Error and RuntimeException classes. All other exceptions descend from the Exception class.
Programmers who encounter exceptions have two options: handle them with a try/catch block or re-declare them in order to pass them along. It’s good practice to handle exceptions whenever possible and pass them along when it doesn’t make sense to handle them immediately.
Additional Exercises
1. Write a CustomerNotFoundException class. Include a constructor that requires a String parameter. Override the toString() method so it will print the message. Use a main() method to test-throw the exception.
2. Write a class with a main() method that throws the Exception class. In the code body, call Thread.sleep() with some duration less than 10 seconds. Also create a Socket object that connects to foo.bar at port 80.
3. Write a Server class with a method that constructs a ServerSocket object (from the java.net package), using port 22222. Use the compiler to tell you which exception(s) you must catch for the code to compile. Add a main() method and call the method you wrote from it.
4. Add a method to the Server class from exercise 3 that declares the exception you discovered. Use port 66666 for the ServerSocket constructor. Update the main() method to call this method after the first one. Compile the code. What happens when you run it?
Review Questions
1. Which of the following statements is correct?
A. You can only declare checked exceptions.
B. You can throw Error subclasses.
C. You can only handle Exception subclasses.
D. You cannot extend the Throwable class directly.
2. Which of the following classes is a checked exception?
A. SecurityException
B. IOError
C. UnknownHostException
D. IllegalArgumentException
3. True or false: You can combine checked and unchecked exceptions in one catch block using multi-catch syntax.
4. Which category of Throwable classes is also Serializable?
A. All Exception classes
B. All RuntimeException classes
C. All Error classes
D. All of the above
5. True or false: You can throw any Java class as an exception, and you can declare any Java class as a return type.
6. When are you required to use a finally block?
A. Never
B. When the program code doesn’t terminate on its own
C. When there are two or more catch blocks
D. Any time you use multi-catch syntax
7. Which exception will the following code snippet throw?
Object obj = new Integer(3);String str = (String)obj;System.out.println(str);
A. IllegalArgumentException
B. NumberFormatException
C. ClassCastException
D. UnsupportedOperationException
8. What will happen if you add the statement System.out.println(5 / 0); to a working main() method?
A. It will not compile.
B. It will not run.
C. It will run and throw an IllegalArgumentException.
D. It will run and throw an ArithmeticException.
9. Which of the following lists is a correct sequence for catching exceptions?
A. SecurityException, IOError, Exception
B. NumberFormatException, RuntimeException, ClassCastException
C. IllegalArgumentException, Exception, RuntimeException
10. The UnsupportedOperationException class is used closely by which core JDK package?
A. java.net
B. java.io
C. java.util
D. java.lang

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.137.12