Chapter 12

Looking Good When Things Take Unexpected Turns

In This Chapter

arrow Recovering from bad input and other nasty situations

arrow Making your code (more or less) crash proof

arrow Defining your own exception class

September 9, 1945: A moth flies into one of the relays of the Harvard Mark II computer and gums up the works. This becomes the first recorded case of a real computer bug.

Armed with nothing but this good guess, Bright writes a small FORTRAN program and tries to compile it on his IBM 704. (The IBM 704 lives in its own specially built, 2,000-square-foot room. With vacuum tubes instead of transistors, the machine has a whopping 32K of RAM. The operating system has to be loaded from tape before the running of each program, and a typical program takes between two and four hours to run.) After the usual waiting time, Bright’s attempt to compile a FORTRAN program comes back with a single error — a missing comma in one of the statements. Bright corrects the error, and the program runs like a charm.

July 22, 1962: Mariner I, the first U.S. spacecraft aimed at another planet, is destroyed when it behaves badly four minutes after launch. The bad behavior is attributed to a missing bar (like a hyphen) in the formula for the rocket’s velocity.

Around the same time, orbit computation software at NASA is found to contain the incorrect statement DO 10 I=1.10 (instead of the correct DO 10 I=1,10). In modern notation, this is like writing do10i = 1.10 in place of for (int i=1; i<=10; i++). The change from a comma to a period turns a loop into an assignment statement.

January 1, 2000: The Year 2000 Problem wreaks havoc on the modern world.

Any historically accurate facts in these notes were borrowed from the following sources: the Computer Folklore newsgroup (alt.folklore.computers, which you can access through http://groups.google.com), the Free On-line Dictionary of Computing (http://foldoc.org), the “Looking Back” column in Computer magazine (www.computer.org/computer), and the web pages of the IEEE (www.computer.org/history).

Handling Exceptions

You’re taking inventory. This means counting item after item, box after box, and marking the numbers of such things on log sheets, in little handheld gizmos, and into forms on computer keyboards. A particular part of the project involves entering the number of boxes that you find on the Big Dusty Boxes That Haven’t Been Opened Since Year One shelf. Rather than break the company’s decades-old habit, you decide not to open any of these boxes. You arbitrarily assign the value $3.25 to each box.

Listing 12-1 shows the software to handle this bit of inventory. The software has a flaw, which is revealed in Figure 12-1. When the user enters a whole number value, things are okay. But when the user enters something else (like the number 3.5), the program comes crashing to the ground. Surely something can be done about this. Computers are stupid, but they’re not so stupid that they should fail royally when a user enters an improper value.

Listing 12-1: Counting Boxes

import static java.lang.System.out;

import java.util.Scanner;

import java.text.NumberFormat;

class InventoryA {

public static void main(String args[]) {

final double boxPrice = 3.25;

Scanner keyboard = new Scanner(System.in);

NumberFormat currency =

NumberFormat.getCurrencyInstance();

out.print(“How many boxes do we have? “);

String numBoxesIn = keyboard.next();

int numBoxes = Integer.parseInt(numBoxesIn);

out.print(“The value is “);

out.println(currency.format(numBoxes * boxPrice));

}

}

Figure 12-1: Three separate runs of the code in Listing 12-1.

9781118128329 fg1201.tif

The key to fixing a program bug is examining the message that appears when the program crashes. The inventory program’s message says java.lang.NumberFormatException. That means a class named NumberFormatException is in the java.lang API package. Somehow, the call to Integer.parseInt brought this NumberFormatException class out of hiding.

cross-reference.epsFor a brief explanation of the Integer.parseInt method, see Chapter 11.

Well, here’s what’s going on. The Java programming language has a mechanism called exception handling. With exception handling, a program can detect that things are about to go wrong and respond by creating a brand-new object. In the official terminology, the program is said to be throwing an exception. That new object, an instance of the Exception class, is passed like a hot potato from one piece of code to another until some piece of code decides to catch the exception. When the exception is caught, the program executes some recovery code, buries the exception, and moves on to the next normal statement as if nothing had ever happened. The process is illustrated in Figure 12-2.

The whole thing is done with the aid of several Java keywords. These keywords are as follows:

check.png throw: Creates a new exception object.

check.png throws: Passes the buck from a method up to whatever code called the method.

check.png try: Encloses code that has the potential to create a new exception object. In the usual scenario, the code inside a try clause contains calls to methods whose code can create one or more exceptions.

check.png catch: Deals with the exception, buries it, and then moves on.

So, the truth is out. Through some chain of events like the one shown in Figure 12-2, the method Integer.parseInt can throw a NumberFormatException. When you call Integer.parseInt, this NumberFormatException is passed on to you.

tip.eps The Java API (Application Programming Interface) documentation for the parseInt method says, “Throws: NumberFormatException — if the string does not contain a parsable integer.” Once in a while, reading the documentation actually pays.

If you call yourself a hero, you’d better catch the exception so that all the other code can get on with its regular business. Listing 12-2 shows the catching of an exception.

Figure 12-2: Throwing, passing, and catching an exception.

9781118128329 fg1202.eps

Listing 12-2: A Hero Counts Boxes

import static java.lang.System.out;

import java.util.Scanner;

import java.text.NumberFormat;

class InventoryB {

public static void main(String args[]) {

final double boxPrice = 3.25;

Scanner keyboard = new Scanner(System.in);

NumberFormat currency =

NumberFormat.getCurrencyInstance();

out.print(“How many boxes do we have? “);

String numBoxesIn = keyboard.next();

try {

int numBoxes = Integer.parseInt(numBoxesIn);

out.print(“The value is “);

out.println(

currency.format(numBoxes * boxPrice));

} catch (NumberFormatException e) {

out.println(“That’s not a number.”);

}

}

}

Figure 12-3 shows three runs of the code from Listing 12-2. When a misguided user types three instead of 3, the program maintains its cool by displaying That’s not a number. The trick is to enclose the call to Integer.parseInt inside a try clause. If you do this, the computer watches for exceptions when any statement inside the try clause is executed. If an exception is thrown, the computer jumps from inside the try clause to a catch clause below it. In Listing 12-2, the computer jumps directly to the catch (NumberFormatException e) clause. The computer executes the println statement inside the clause and then marches on with normal processing. (If there were statements in Listing 12-2 after the end of the catch clause, the computer would go on and execute them.)

Figure 12-3: Three runs of the code in Listing 12-2.

9781118128329 fg1203.tif

technicalstuff.eps An entire try-catch assembly — complete with a try clause, catch clause, and what have you — is called a try statement. Sometimes, for emphasis, I call it a try-catch statement.

The parameter in a catch clause

Take a look at the catch clause in Listing 12-2 and pay particular attention to the words (NumberFormatException e). This looks a lot like a method’s parameter list, doesn’t it? In fact, every catch clause is like a little mini-method with its own parameter list. The parameter list always has an exception type name and then a parameter.

In Listing 12-2, I don’t do anything with the catch clause’s e parameter, but I certainly could if I wanted to. Remember, the exception that’s thrown is an object — an instance of the NumberFormatException class. When an exception is caught, the computer makes the catch clause’s parameter refer to that exception object. In other words, the name e stores a bunch of information about the exception. To take advantage of this, you can call some of the exception object’s methods.

} catch (NumberFormatException e) {

out.println(“Message: ***” + e.getMessage() + “***”);

e.printStackTrace();

}

With this new catch clause, a run of the inventory program may look like the run shown in Figure 12-4. When you call getMessage, you fetch some detail about the exception. (In Figure 12-4, the detail is Message: ***For input string: “three”***.) When you call printStackTrace, you get some additional information; namely, a display showing the methods that were running at the moment when the exception was thrown. (In Figure 12-4, the display includes Integer.parseInt and the main method.) Both getMessage and printStackTrace present information to help you find the source of the program’s difficulties.

Figure 12-4: Calling an exception object’s methods.

9781118128329 fg1204.tif

technicalstuff.eps When you mix System.out.println calls with printStackTrace calls, the order in which Java displays the information is not predictable. For example, in Figure 12-4, the text Message: ***For input string: “three”*** may appear before or after the stack trace. If the ordering of this output matters to you, change out.println(“Message: ***” to System.err.println(“Message: ***”.

Exception types

So what else can go wrong today? Are there other kinds of exceptions — things that don’t come from the NumberFormatException class? Sure, plenty of different exception types are out there. You can even create one of your own. You wanna try? If so, look at Listings 12-3 and 12-4.

Listing 12-3: Making Your Own Kind of Exception

@SuppressWarnings(“serial”)

class OutOfRangeException extends Exception {

}

Listing 12-4: Using Your Custom Made Exception

import static java.lang.System.out;

import java.util.Scanner;

import java.text.NumberFormat;

class InventoryC {

public static void main(String args[]) {

final double boxPrice = 3.25;

Scanner keyboard = new Scanner(System.in);

NumberFormat currency =

NumberFormat.getCurrencyInstance();

out.print(“How many boxes do we have? “);

String numBoxesIn = keyboard.next();

try {

int numBoxes = Integer.parseInt(numBoxesIn);

if (numBoxes < 0) {

throw new OutOfRangeException();

}

out.print(“The value is “);

out.println(

currency.format(numBoxes * boxPrice));

} catch (NumberFormatException e) {

out.println(“That’s not a number.”);

} catch (OutOfRangeException e) {

out.print(numBoxesIn);

out.println(“? That’s impossible!”);

}

}

}

Listings 12-3 and 12-4 remedy a problem that cropped up in Figure 12-3. Look at the last of the three runs in Figure 12-3. The user reports that the shelves have –25 boxes, and the computer takes this value without blinking an eye. The truth is that you would need a black hole (or some other exotic space-time warping phenomenon) to have a negative number of boxes on any shelf in your warehouse. So the program should get upset if the user enters a negative number of boxes, which is what the code in Listing 12-4 does. To see the upset code, look at Figure 12-5.

Figure 12-5: Three runs of the code from Listings 12-3 and 12-4.

9781118128329 fg1205.tif

The code in Listing 12-3 declares a new kind of exception class — OutOfRangeException. In many situations, typing a negative number would be just fine, so OutOfRangeException isn’t built in to the Java API. However, in the inventory program, a negative number should be flagged as an anomaly.

The OutOfRangeException class in Listing 12-3 wins the award for the shortest self-contained piece of code in the book. The class’s code is just a declaration line and an empty pair of braces. The code’s operative phrase is extends Exception. Being a subclass of the Java API Exception class allows any instance of the OutOfRangeException class to be thrown.

Back in Listing 12-4, a new OutOfRangeException instance is thrown. When this happens, the catch clause (OutOfRangeException e) catches the instance. The clause echoes the user’s input and displays the message That’s impossible!

cross-reference.eps The text @SuppressWarnings(“serial”) in Listing 12-3 is a Java annotation. For an introduction to annotations, see Chapter 8. For a few words about the SuppressWarnings annotation, see Chapter 9.

Who’s going to catch the exception?

Take one more look at Listing 12-4. Notice that more than one catch clause can accompany a single try clause. When an exception is thrown inside a try clause, the computer starts going down the accompanying list of catch clauses. The computer starts at whatever catch clause comes immediately after the try clause and works its way down the program’s text.

For each catch clause, the computer asks itself, “Is the exception that was just thrown an instance of the class in this clause’s parameter list?”

check.png If not, the computer skips this catch clause and moves on to the next catch clause in line.

check.png If so, the computer executes this catch clause and then skips past all the other catch clauses that come with this try clause. The computer goes on and executes whatever statements come after the whole try-catch statement.

For some concrete examples, see Listings 12-5 and 12-6.

Listing 12-5: Yet Another Exception

@SuppressWarnings(“serial”)

class NumberTooLargeException

extends OutOfRangeException {

}

Listing 12-6: Where Does the Buck Stop?

import static java.lang.System.out;

import java.util.Scanner;

import java.text.NumberFormat;

class InventoryD {

public static void main(String args[]) {

final double boxPrice = 3.25;

Scanner keyboard = new Scanner(System.in);

NumberFormat currency =

NumberFormat.getCurrencyInstance();

out.print(“How many boxes do we have? “);

String numBoxesIn = keyboard.next();

try {

int numBoxes = Integer.parseInt(numBoxesIn);

if (numBoxes < 0) {

throw new OutOfRangeException();

}

if (numBoxes > 1000) {

throw new NumberTooLargeException();

}

out.print(“The value is “);

out.println(

currency.format(numBoxes * boxPrice));

}

catch (NumberFormatException e) {

out.println(“That’s not a number.”);

}

catch (OutOfRangeException e) {

out.print(numBoxesIn);

out.println(“? That’s impossible!”);

}

catch (Exception e) {

out.print(“Something went wrong, “);

out.print(“but I’m clueless about what “);

out.println(“it actually was.”);

}

out.println(“That’s that.”);

}

}

To run the code in Listings 12-5 and 12-6, you need one additional Java program file. You need the OutOfRangeException class in Listing 12-3.

Listing 12-6 addresses the scenario in which you have limited shelf space. You don’t have room for more than 1,000 boxes, but once in a while, the program asks how many boxes you have, and somebody enters the number 100000 by accident. In cases like this, Listing 12-6 does a quick reality check. Any number of boxes over 1,000 is tossed out as being unrealistic.

Listing 12-6 watches for a NumberTooLargeException, but to make life more interesting, Listing 12-6 doesn’t have a catch clause for the NumberTooLargeException. In spite of this, everything still works out just fine. It’s fine because NumberTooLargeException is declared to be a subclass of OutOfRangeException, and Listing 12-6 has a catch clause for the OutOfRangeException.

You see, because NumberTooLargeException is a subclass of OutOfRangeException, any instance of NumberTooLargeException is just a special kind of OutOfRangeException. So in Listing 12-6, the computer may start looking for a clause to catch a NumberTooLargeException. When the computer stumbles upon the OutOfRangeException catch clause, the computer says, “Okay, I’ve found a match. I’ll execute the statements in this catch clause.”

To keep from having to write this whole story over and over again, I introduce some new terminology. I say that the catch clause with parameter OutOfRangeException matches the NumberTooLargeException that’s been thrown. I call this catch clause a matching catch clause.

The following bullets describe different things that the user may do and how the computer responds. As you read through the bullets, you can follow along by looking at the runs shown in Figure 12-6.

Figure 12-6: Four runs of the code from Listing 12-6.

9781118128329 fg1206.tif

check.png The user enters an ordinary whole number, like the number 3. All the statements in the try clause are executed. Then the computer skips past all the catch clauses and executes the code that comes immediately after all the catch clauses. (See Figure 12-7.)

check.png The user enters something that’s not a whole number, like the word fish. The code throws a NumberFormatException. The computer skips past the remaining statements in the try clause. The computer executes the statements inside the first catch clause — the clause whose parameter is of type NumberFormatException. Then the computer skips past the second and third catch clauses and executes the code that comes immediately after all the catch clauses. (See Figure 12-8.)

Figure 12-7: No exception is thrown.

9781118128329 fg1207.eps

Figure 12-8: A NumberFormatException is thrown.

9781118128329 fg1208.eps

check.png The user enters a negative number, like the number –25. The code throws an OutOfRangeException. The computer skips past the remaining statements in the try clause. The computer even skips past the statements in the first catch clause. (After all, an OutOfRangeException isn’t any kind of a NumberFormatException. The catch clause with parameter NumberFormatException isn’t a match for this OutOfRangeException.) The computer executes the statements inside the second catch clause — the clause whose parameter is of type OutOfRangeException. Then the computer skips past the third catch clause and executes the code that comes immediately after all the catch clauses. (See Figure 12-9.)

Figure 12-9: An OutOfRangeException is thrown.

9781118128329 fg1209.eps

check.png The user enters an unrealistically large number, like the number 1001. The code throws a NumberTooLargeException. The computer skips past the remaining statements in the try clause. The computer even skips past the statements in the first catch clause. (After all, a NumberTooLargeException isn’t any kind of NumberFormatException.)

But, according to the code in Listing 12-5, NumberTooLargeException is a subclass of OutOfRangeException. When the computer reaches the second catch clause, the computer says, “Hmm! A NumberTooLargeException is a kind of OutOfRangeException. I’ll execute the statements in this catch clause — the clause with parameter of type OutOfRangeException.” In other words, it’s a match.

So, the computer executes the statements inside the second catch clause. Then the computer skips the third catch clause and executes the code that comes immediately after all the catch clauses. (See Figure 12-10.)

Figure 12-10: A NumberTooLargeException is thrown.

9781118128329 fg1210.eps

check.png Something else, something very unpredictable, happens (I don’t know what). With my unending urge to experiment, I reached into the try clause of Listing 12-6 and added a statement that throws an IOException. No reason — I just wanted to see what would happen.

When the code threw an IOException, the computer skipped past the remaining statements in the try clause. Then the computer skipped past the statements in the first and second catch clauses. When the computer reached the third catch clause, I could hear the computer say, “Hmm! An IOException is a kind of Exception. I’ve found a matching catch clause — a clause with a parameter of type Exception. I’ll execute the statements in this catch clause.”

So, the computer executed the statements inside the third catch clause. Then the computer executed the code that comes immediately after all the catch clauses. (See Figure 12-11.)

Figure 12-11: An IOException is thrown.

9781118128329 fg1211.eps

When the computer looks for a matching catch clause, the computer latches on to the topmost clause that fits one of the following descriptions:

check.png The clause’s parameter type is the same as the type of the exception that was thrown.

check.png The clause’s parameter type is a superclass of the exception’s type.

If a better match appears farther down the list of catch clauses, that’s just too bad. For instance, imagine that you added a catch clause with a parameter of type NumberTooLargeException to the code in Listing 12-6. Imagine, also, that you put this new catch clause after the catch clause with parameter of type OutOfRangeException. Then, because NumberTooLargeException is a subclass of the OutOfRangeException class, the code in your new NumberTooLargeException clause would never be executed. That’s just the way the cookie crumbles.

Java 7 and the multi-catch clause

Starting with Java 7, you can catch more than one kind of exception in a single catch clause. For example, in a particular inventory program, you might not want to distinguish between the throwing of a NumberFormatException and your own OutOfRangeException. In that case, you can rewrite part of Listing 12-6 as follows:

try {

int numBoxes = Integer.parseInt(numBoxesIn);

if (numBoxes < 0) {

throw new OutOfRangeException();

}

if (numBoxes > 1000) {

throw new NumberTooLargeException();

}

out.print(“The value is “);

out.println(

currency.format(numBoxes * boxPrice));

}

catch (NumberFormatException | OutOfRangeException e) {

out.print(numBoxesIn);

out.println(“? That’s impossible!”);

}

catch (Exception e) {

out.print(“Something went wrong, “);

out.print(“but I’m clueless about what “);

out.println(“it actually was.”);

}

The pipe symbol, |, tells Java 7 to catch either a NumberFormatException or an OutOfRangeException. If you throw an exception of either type, the program displays the value of numBoxesIn followed by the text ? That’s impossible! If you throw an exception that is neither a NumberFormatException nor an OutOfRangeException, the program jumps to the last catch clause and displays Something went wrong, but I’m clueless . . .

Throwing caution to the wind

Are you one of those obsessive-compulsive types? Do you like to catch every possible exception before the exception can possibly crash your program? Well, watch out. Java doesn’t let you become paranoid. You can’t catch an exception if the exception has no chance of being thrown.

Consider the following code. The code has a very innocent i++ statement inside a try clause. That’s fair enough. But then the code’s catch clause is pretending to catch an IOException.

// Bad code!

try {

i++;

} catch (IOException e) {

e.printStackTrace();

}

Who is this catch clause trying to impress? A statement like i++ doesn’t do any input or output. The code inside the try clause can’t possibly throw an IOException. So the compiler comes back and says, “Hey, catch clause. Get real. Get off your high horse.” Well, to be a bit more precise, the compiler’s reprimand reads as follows:

exception java.io.IOException is never thrown in body of corresponding try statement

Doing useful things

So far, each example in this chapter catches an exception, prints a “bad input” message, and then closes up shop. Wouldn’t it be nice to see a program that actually carries on after an exception has been caught? Well, it’s time for something nice. Listing 12-7 has a try-catch statement inside a loop. The loop keeps running until the user types something sensible.

Listing 12-7: Keep Pluggin’ Along

import static java.lang.System.out;

import java.util.Scanner;

import java.text.NumberFormat;

class InventoryLoop {

public static void main(String args[]) {

final double boxPrice = 3.25;

boolean gotGoodInput = false;

Scanner keyboard = new Scanner(System.in);

NumberFormat currency =

NumberFormat.getCurrencyInstance();

do {

out.print(“How many boxes do we have? “);

String numBoxesIn = keyboard.next();

try {

int numBoxes = Integer.parseInt(numBoxesIn);

out.print(“The value is “);

out.println

(currency.format(numBoxes * boxPrice));

gotGoodInput = true;

} catch (NumberFormatException e) {

out.println();

out.println(“That’s not a number.”);

}

} while (!gotGoodInput);

out.println(“That’s that.”);

}

}

Figure 12-12 shows a run of the code from Listing 12-7. In the first three attempts, the user types just about everything except a valid whole number. At last, the fourth attempt is a success. The user types 3, and the computer leaves the loop.

Figure 12-12: A run of the code in Listing 12-7.

9781118128329 fg1212.tif

Our friends, the good exceptions

A rumor is going around that Java exceptions always come from unwanted, erroneous situations. Although there’s some truth to this rumor, the rumor isn’t entirely accurate. Occasionally, an exception arises from a normal, expected occurrence. Take, for instance, the detection of the end of a file. The following code makes a copy of a file:

try {

while (true) {

dataOut.writeByte(dataIn.readByte());

}

} catch (EOFException e) {

numFilesCopied = 1;

}

To copy bytes from dataIn to dataOut, you just go into a while loop. With its true condition, the while loop is seemingly endless. But eventually, you reach the end of the dataIn file. When this happens, the readByte method throws an EOFException (an end-of-file exception). The throwing of this exception sends the computer out of the try clause and out of the while loop. From there, you do whatever you want to do in the catch clause and then proceed with normal processing.

Handle an Exception or Pass the Buck

So you’re getting to know Java, hey? What? You say you’re all the way up to Chapter 12? I’m impressed. You must be a hard worker. But remember, all work and no play. . . .

So, how about taking a break? A little nap could do you a world of good. Is ten seconds okay? Or is that too long? Better make it five seconds.

Listing 12-8 has a program that’s supposed to pause its execution for five seconds. The problem is that the program in Listing 12-8 is incorrect. Take a look at Listing 12-8 for a minute, and then I’ll tell you what’s wrong with it.

Listing 12-8: An Incorrect Program

/*

* This code does not compile.

*/

import static java.lang.System.out;

class NoSleepForTheWeary {

public static void main(String args[]) {

out.print(“Excuse me while I nap “);

out.println(“for just five seconds...”);

takeANap();

out.println(“Ah, that was refreshing.”);

}

static void takeANap() {

Thread.sleep(5000);

}

}

The strategy in Listing 12-8 isn’t bad. The idea is to call the sleep method, which is defined in the Java API. This sleep method belongs to the API Thread class. When you call the sleep method, the number that you feed it is a number of milliseconds. So, Thread.sleep(5000) means pause for five seconds.

The problem is that the code inside the sleep method can throw an exception. This kind of exception is an instance of the InterruptedException class. When you try to compile the code in Listing 12-8, you get a message such as

unreported exception java.lang.InterruptedException;

must be caught or declared to be thrown

Maybe the message reads

Unhandled exception type InterruptedException

One way or another, the message is unwelcome.

technicalstuff.eps For the purpose of understanding exceptions in general, you don’t need to know exactly what an InterruptedException is. All you really have to know is that a call to Thread.sleep can throw one of these InterruptedException objects. But if you’re really curious, an InterruptedException is thrown when some code interrupts some other code’s sleep. Imagine that you have two pieces of code running at the same time. One piece of code calls the Thread.sleep method. At the same time, another piece of code calls the interrupt method. By calling the interrupt method, the second piece of code brings the first code’s Thread.sleep method to a screeching halt. The Thread.sleep method responds by spitting out an InterruptedException.

Now, the Java programming language has two different kinds of exceptions. They’re called checked and unchecked exceptions:

check.png The potential throwing of a checked exception must be acknowledged in the code.

check.png The potential throwing of an unchecked exception doesn’t need to be acknowledged in the code.

An InterruptedException is one of Java’s checked exception types. When you call a method that has the potential to throw an InterruptedException, you need to acknowledge that exception in the code.

Now, when I say that an exception is acknowledged in the code, what do I really mean?

// The author wishes to thank that InterruptedException,

// without which this code could not have been written.

No, that’s not what it means to be acknowledged in the code. Acknowledging an exception in the code means one of two things:

check.png The statements (including method calls) that can throw the exception are inside a try clause. That try clause has a catch clause with a matching exception type in its parameter list.

check.png The statements (including method calls) that can throw the exception are inside a method that has a throws clause in its header. The throws clause contains a matching exception type.

If you’re confused by the wording of these two bullets, don’t worry. The next two listings illustrate the points made in the bullets.

In Listing 12-9, the method call that can throw an InterruptedException is inside a try clause. That try clause has a catch clause with exception type InterruptedException.

Listing 12-9: Acknowledging with a try-catch Statement

import static java.lang.System.out;

class GoodNightsSleepA {

public static void main(String args[]) {

out.print(“Excuse me while I nap “);

out.println(“for just five seconds...”);

takeANap();

out.println(“Ah, that was refreshing.”);

}

static void takeANap() {

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

out.println(“Hey, who woke me up?”);

}

}

}

It’s my custom, at this point in a section, to remind you that a run of Listing Such-and-Such is shown in Figure So-and-So. But the problem here is that Figure 12-13 doesn’t do justice to the code in Listing 12-9. When you run the program in Listing 12-9, the computer displays Excuse me while I nap for just five seconds, pauses for five seconds, and then displays Ah, that was refreshing. The code works because the call to the sleep method, which can throw an InterruptedException, is inside a try clause. That try clause has a catch clause whose exception is of type InterruptedException.

Figure 12-13: There’s a five-second pause before the “Ah” line.

9781118128329 fg1213.tif

So much for acknowledging an exception with a try-catch statement. You can acknowledge an exception another way, shown in Listing 12-10.

Listing 12-10: Acknowledging with throws

import static java.lang.System.out;

class GoodNightsSleepB {

public static void main(String args[]) {

out.print(“Excuse me while I nap “);

out.println(“for just five seconds...”);

try {

takeANap();

} catch (InterruptedException e) {

out.println(“Hey, who woke me up?”);

}

out.println(“Ah, that was refreshing.”);

}

static void takeANap() throws InterruptedException {

Thread.sleep(5000);

}

}

To see a run of the code in Listing 12-10, refer to Figure 12-13. Once again, Figure 12-13 fails to capture the true essence of the run, but that’s okay. Just remember that in Figure 12-13, the computer pauses for five seconds before it displays Ah, that was refreshing.

The important part of Listing 12-10 is in the takeANap method’s header. That header ends with throws InterruptedException. By announcing that it throws an InterruptedException, method takeANap passes the buck. What this throws clause really says is, “I realize that a statement inside this method has the potential to throw an InterruptedException, but I’m not acknowledging the exception in a try-catch statement. Java compiler, please don’t bug me about this. Instead of having a try-catch statement, I’m passing the responsibility for acknowledging the exception to the main method (the method that called the takeANap method).”

Indeed, in the main method, the call to takeANap is inside a try clause. That try clause has a catch clause with a parameter of type InterruptedException. So everything is okay. Method takeANap passes the responsibility to the main method, and the main method accepts the responsibility with an appropriate try-catch statement. Everybody’s happy. Even the Java compiler is happy.

To better understand the throws clause, imagine a volleyball game in which the volleyball is an exception. When a player on the other team serves, that player is throwing the exception. The ball crosses the net and comes right to you. If you pound the ball back across the net, you’re catching the exception. But if you pass the ball to another player, you’re using the throws clause. In essence, you’re saying, “Here, other player. You deal with this exception.”

remember.eps A statement in a method can throw an exception that’s not matched by a catch clause. This includes situations in which the statement throwing the exception isn’t even inside a try block. When this happens, execution of the program jumps out of the method that contains the offending statement. Execution jumps back to whatever code called the method in the first place.

tip.epsA method can name more than one exception type in its throws clause. Just use commas to separate the names of the exception types, as in the following example:

throws InterruptedException, IOException,

ArithmeticException

The Java API has hundreds of exception types. Several of them are subclasses of the RuntimeException class. Anything that’s a subclass of RuntimeException (or a sub-subclass, sub-sub-subclass, and so on) is unchecked. Any exception that’s not a descendent of RuntimeException is checked. The unchecked exceptions include things that would be hard for the computer to predict. Such things include the NumberFormatException (of Listings 12-2, 12-4, and others), the ArithmeticException, the IndexOutOfBoundsException, the infamous NullPointerException, and many others. When you write Java code, much of your code is susceptible to these exceptions, but enclosing the code in try clauses (or passing the buck with throws clauses) is completely optional.

The Java API also has its share of checked exceptions. The computer can readily detect exceptions of this kind. So Java insists that, for an exception of this kind, any potential exception-throwing statement is acknowledged with either a try statement or a throws clause. Java’s checked exceptions include the InterruptedException (Listings 12-9 and 12-10), the IOException, the SQLException, and a gang of other interesting exceptions.

Finishing the Job with a finally Clause

Once upon a time, I was a young fellow, living with my parents in Philadelphia, just starting to drive a car. I was heading toward a friend’s house and thinking about who knows what when another car came from nowhere and bashed my car’s passenger door. This kind of thing is called a RunARedLightException.

Anyway, both cars were still drivable, and we were right in the middle of a busy intersection. To avoid causing a traffic jam, we both pulled over to the nearest curb. I fumbled for my driver’s license (which had a very young picture of me on it), and opened the door to get out of my car.

And that’s when the second accident happened. As I was getting out of my car, a city bus was coming by. The bus hit me and rolled me against my car a few times. This kind of thing is called a DealWithLawyersException.

The truth is that everything came out just fine. I was bruised but not battered. My parents paid for the damage to the car, so I never suffered any financial consequences. (I managed to pass on the financial burden by putting the RunARedLightException into my throws clause.)

This incident helps to explain why I think the way I do about exception handling. In particular, I wonder, “What happens if, while the computer is recovering from one exception, a second exception is thrown?” After all, the statements inside a catch clause aren’t immune to calamities.

Well, the answer to this question is anything but simple. For starters, you can put a try statement inside a catch clause. This protects you against unexpected, potentially embarrassing incidents that can crop up during the execution of the catch clause. But when you start worrying about cascading exceptions, you open up a very slimy can of worms. The number of scenarios is large, and things can become complicated very quickly.

One not-too-complicated thing that you can do is to create a finally clause. Like a catch clause, a finally clause comes after a try clause. The big difference is that the statements in a finally clause are executed whether or not an exception is thrown. The idea is, “No matter what happens, good or bad, execute the statements inside this finally clause.” Listing 12-11 has an example.

Listing 12-11: Jumping Around

import static java.lang.System.out;

class DemoFinally {

public static void main(String args[]) {

try {

doSomething();

} catch (Exception e) {

out.println(“Exception caught in main.”);

}

}

static void doSomething() {

try {

out.println(0 / 0);

} catch (Exception e) {

out.println(

“Exception caught in doSomething.”);

out.println(0 / 0);

} finally {

out.println(“I’ll get printed.”);

}

out.println(“I won’t get printed.”);

}

}

Normally, when I think about a try statement, I think about the computer recovering from an unpleasant situation. The recovery takes place inside a catch clause, and then the computer marches on to whatever statements come after the try statement. Well, if something goes wrong during execution of a catch clause, this picture can start looking different.

Listing 12-11 gets a workout in Figure 12-14. First, the main method calls doSomething. Then, the stupid doSomething method goes out of its way to cause trouble. The doSomething method divides 0 by 0, which is illegal and undoable in anyone’s programming language. This foolish action by the doSomething method throws an ArithmeticException, which is caught by the try statement’s one and only catch clause.

Figure 12-14: Running the code from Listing 12-11.

9781118128329 fg1214.tif

Inside the catch clause, that lowlife doSomething method divides 0 by 0 again. This time, the statement that does the division isn’t inside a protective try clause. That’s okay, because an ArithmeticException isn’t checked. (It’s one of those RuntimeException subclasses. It’s an exception that doesn’t have to be acknowledged in a try or a throws clause. For details, see the previous section.)

Well, checked or not, the throwing of another ArithmeticException causes control to jump out of the doSomething method. But, before leaving the doSomething method, the computer executes the try statement’s last will and testament — namely, the statements inside the finally clause. That’s why, in Figure 12-14, you see the words I’ll get printed.

Interestingly enough, you don’t see the words I won’t get printed in Figure 12-14. Because the catch clause’s execution throws its own uncaught exception, the computer never makes it down past the try-catch-finally statement.

So, the computer goes back to where it left off in the main method. Back in the main method, word of the doSomething method’s ArithmeticException mishaps causes execution to jump into a catch clause. The computer prints Exception caught in main, and then this terrible nightmare of a run is finished.

Close Those Files!

In the year 4839, the inhabitants of Earth will open a time capsule containing Java For Dummies. They’ll notice that several of the book’s examples possess a fatal flaw. “In Chapter 8, Barry reads from a disk file named EmployeeInfo.txt. His DoPayroll program grabs ahold of this resource (this file that normally lives outside of his DoPayroll program). But his DoPayroll program never releases the resource. In early third millennium terminology, Barry opens a file in the beginning of his program, but doesn’t close the file later in the program.”

Barry did this because he didn’t want to burden his readers with details about closing files. For many simple examples, Java closes a program’s files automatically when the program stops running. But in the year 2978, a reader follows Barry’s example and fails to explicitly close files. This oversight causes the Great Robot Blight of 2980, which leads to the failure of the post-post-post-industrial economy and the eventual cancellation of American Idol.

“So Barry Burd is responsible for all our problems,” say the Earth’s inhabitants in 4839. “Let’s not remove him from his cryogenic freezer.”

How to close a file

In hopes of seeing the year 4840, I add one line to the code in Listing 8-2. The listing already contains the following statement:

Scanner diskScanner =

new Scanner(new File(“EmployeeInfo.txt”));

So at the end of the program’s main method, I add

diskScanner.close();

Of course, I can add this call to the close method at any point in the program. My best strategy is to call close immediately after my last use of the EmployeeInfo.txt file.

At this point in the book, the people of 4839 will probably say “Barry added this file-closing business as an afterthought. Closing files has nothing to do with the rest of Chapter 12.” But the people of 4839 will be wrong.

A try statement with resources

The trouble with an ordinary call to the close method is that things can go wrong before Java reaches the close call. Listing 12-12 is almost identical to Listing 8-2. Listing 12-12 has only one additional statement.

Listing 12-12: Close the File?

import java.util.Scanner;

import java.io.File;

import java.io.IOException;

class DoPayroll {

public static void main(String args[])

throws IOException {

Scanner diskScanner =

new Scanner(new File(“EmployeeInfo.txt”));

for (int empNum = 1; empNum <= 3; empNum++) {

payOneEmployee(diskScanner);

}

diskScanner.close();

}

static void payOneEmployee(Scanner aScanner) {

Employee anEmployee = new Employee();

anEmployee.setName(aScanner.nextLine());

anEmployee.setJobTitle(aScanner.nextLine());

anEmployee.cutCheck(aScanner.nextDouble());

aScanner.nextLine();

}

}

Listing 12-12 looks nice, but looks are deceiving. If something goes wrong in the middle of executing payOneEmployee, then the program ends abruptly with a stack trace and a big kaboom. The program never reaches the call to diskScanner.close(), and Barry is still in the cryogenic freezer.

I can enclose some statements inside a try statement, and I can even add a finally clause, but when my program uses several resources (many files, a database and a file, or whatever) the buildup of try statements becomes very complicated. I can make try statements within catch clauses and all kinds of crazy combinations. But Java 7 has a better way to solve the problem. In Java 7, I can create a try-with-resources statement. Listing 12-13 shows you how.

Listing 12-13: Barry’s Redemption

import java.util.Scanner;

import java.io.File;

import java.io.IOException;

class DoPayroll {

public static void main(String args[])

throws IOException {

try (Scanner diskScanner =

new Scanner(new File(“EmployeeInfo.txt”))) {

for (int empNum = 1; empNum <= 3; empNum++) {

payOneEmployee(diskScanner);

}

}

}

static void payOneEmployee(Scanner aScanner) {

Employee anEmployee = new Employee();

anEmployee.setName(aScanner.nextLine());

anEmployee.setJobTitle(aScanner.nextLine());

anEmployee.cutCheck(aScanner.nextDouble());

aScanner.nextLine();

}

}

In Listing 12-13, the declaration of diskScanner is in parentheses after the word try. The parenthesized declaration tells Java 7 to close the diskScanner automatically after execution of the statements in the try clause. You can declare several resources inside one try statement’s parentheses. When you do, Java 7 closes all the resources automatically after execution of the try clause’s statements. You can add catch clauses and a finally clause if you want. You can access all kinds of resources (files, databases, connections to servers, and others) and have peace of mind knowing that Java will sever the connections automatically.

Life is good.

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

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