MORE ABOUT EXCEPTION CLASSES

Một phần của tài liệu java an introductioan to problem solving and programming 6th edition (Trang 717 - 743)

buck n. 1. A counter or marker formerly passed from one poker player to another to indicate an obligation, especially one’s turn to deal. 2. Informal:

Obligation to account for something; responsibility: tried to pass the buck . . .

THE AMERICAN HERITAGE DICTIONARY OF THE ENGLISH LANGUAGE, FOURTH EDITION

The buck stops here.

—SIGN ON HARRY S TRUMAN’S DESK WHILE HE WAS PRESIDENT

In this section, we discuss techniques for using exceptions that go beyond the basics but are still fundamental.

Declaring Exceptions (Passing the Buck)

Sometimes it makes sense to delay handling of an exception. For example, you might have a method whose code throws an exception, but you may not want to catch the exception in that method. Perhaps some programs that use the method should simply end if the exception is thrown, and other programs that use the method should do something else. As a result, you would not know what to do about the exception if you caught it inside the method. In these cases, it makes sense not to catch the exception in the method definition, but instead to have any code that uses the method place the method invocation in a try block and catch the exception in a catch block that follows that try block.

If a method does not catch an exception, it must at least warn programmers that any invocation of the method might possibly throw an exception. This warning is called a throws clause. For example, a method that might throw a

A method might not catch an exception that its code throws

682 CHAPTER 9 / Exception Handling

DivideByZeroException but that does not catch the exception would have a heading like the following one:

public void sampleMethod() throws DivideByZeroException

The part throwsDivideByZeroException is a throws clause. It states that an invocation of the method sampleMethod might throw a DivideByZeroException.

Most exceptions that might be thrown when a method is invoked must be accounted for in one of two ways:

t $BUDIUIFQPTTJCMFFYDFQUJPOJOBcatch block within the method definition.

t %FDMBSFUIFQPTTJCMFFYDFQUJPOCZXSJUJOHBthrowsDMBVTFJOUIFNFUIPET heading and let whoever uses the method worry about how to handle the exception.

In any one method, you can mix these two alternatives, catching some exceptions and declaring others in a throws clause.

You already know about handling exceptions in a catch block. The second technique is a form of “passing the buck.” For example, suppose methodA has athrows clause as follows:

public void methodA() throws DivideByZeroException

In this case, methodA is absolved of the responsibility of catching any exceptions of type DivideByZeroException that might occur when methodA is executed. If, however, the definition of methodB includes an invocation of methodA, methodB must deal with the exception. When methodA adds the throws clause, it is “saying” to methodB, “If you invoke me, you must worry about any DivideByZeroException that I throw.” In effect, methodA has passed the responsibility (“passed the buck”) for any exceptions of type DivideByZeroException from itself to any method that calls it.

Of course, if methodA passes the buck to methodB by including a throws clause in its heading, methodB can also pass the buck to whatever method calls it by including the same throwsDMBVTFJOJUTEFGJOJUJPO#VUJOBXFMMXSJUUFO program, every exception that is thrown should eventually be caught by a catch block in some method that does not pass the buck.

Athrows clause can contain more than one exception type. In such cases, you separate the exception types with commas, as follows:

public int myMethod() throws IOException, DivideByZeroException

*GBEFSJWFEDMBTTPWFSSJEFTBCBTFDMBTTNFUIPEUIBUIBTBthrows clause, you cannot add exceptions to the throws clause of the new overriding method.

A method that does not handle an exception that it throws must have a throws clause in its heading

A method that can throw several different exceptions has only one throws clause

REMEMBER Throwing an Exception Can End a Method

If a method throws an exception, and the exception is not caught inside the method, the method invocation ends immediately after the exception is thrown.

So if this method needs to throw an exception that is not already listed in the throws clause of the overridden method in the base class, the overriding method must handle that exception in try-catch blocks. You can, however, declare fewer exceptions in the throws clause of the overriding method.

Listing 9.7 shows a revision of the program in Listing 9.6 so that the normal case is in a method called doNormalCase. This method can throw a

Athrows clause in an overriding method can declare fewer, but not more, exceptions than the overridden method declares LISTING 9.7 Passing the Buck Using a throws Clause

import java.util.Scanner;

public class DoDivision {

private int numerator;

private int denominator;

private double quotient;

public static void main(String[] args) {

DoDivision doIt = new DoDivision();

try {

doIt.doNormalCase();

}

catch(DivideByZeroException e) {

System.out.println(e.getMessage());

doIt.giveSecondChance();

}

System.out.println("End of program.");

}

public void doNormalCase() throws DivideByZeroException {

System.out.println("Enter numerator:");

Scanner keyboard = new Scanner(System.in);

numerator = keyboard.nextInt();

System.out.println("Enter denominator:");

denominator = keyboard.nextInt();

if (denominator == 0)

throw new DivideByZeroException();

quotient = numerator / (double)denominator;

System.out.println(numerator + "/" + denominator +

" = " + quotient);

}

The method giveSecondChance and the input/output samples are identical to those given in Listing 9.6

684 CHAPTER 9 / Exception Handling

DivideByZeroException, but it does not catch it. Thus, we need to declare this possible exception in a throws DMBVTF JO UIF IFBEJOH PG UIF NFUIPET definition. If we set up our program in this way, the case in which nothing goes wrong is completely isolated and easy to read. It is not even cluttered bytry blocks and catch CMPDLT )PXFWFS XIFO UIF NFUIPEmain calls the methoddoNormalCase, it must do so within a try block.

RECAP ThethrowsClause

If you define a method that might throw an exception of some particular class, normally you either must catch the exception within a catch block in the method definition or declare the exception class by writing a throws clause in the method’s heading.

SYNTAX

public Type Method_Name(Parameter_List) throws List_Of_Exceptions

Body_Of_Method EXAMPLE

public void methodA(int n) throws IOException, MyException

{ ...

}

REMEMBER throw Versus throws

The keyword throw is used to throw an exception, whereas throws is used in a method’s heading to declare an exception. Thus, a throw statementthrows an exception, but a throws clause declares one.

Kinds of Exceptions

Thus far, we have said that, in most cases, an exception must either be caught in a catch block or be declared in a throws DMBVTF JO B NFUIPET IFBEJOH That is the basic rule, but there are exceptions to this rule. (An exception to a rule about exceptions! Seems reasonable enough.) Java has some exceptional exceptions that you do not need to account for in this way—although you can catch them in a catch block if you want to.

All Java exceptions are categorized as either checked or unchecked. A checked exception must either be caught in a catch block or declared in a

throws clause. Such exceptions often indicate serious problems that likely should lead to program termination. The exceptions BadStringOperationException, ClassNotFoundException, IOException, and NoSuchMethodException— mentioned earlier in this chapter—are all checked exceptions in the Java Class Library.

An unchecked, or run-time, exception need not be caught in a catch block or declared in a throws clause. These exceptions usually indicate that something is wrong with your code and that you should fix it. Normally, you would not have written a throw statement for these exceptions. They are usually thrown during the evaluation of an expression or by a method in predefined classes. For example, if your program attempts to use an array index that is either too small or too large, an ArrayIndexOutOfBoundsException occurs. If an arithmetic operation causes a problem, such as a division by zero, an ArithmeticException occurs. For such exceptions, you should repair your code, not add a catchCMPDL/PUFUIBUBOVODBVHIUSVOUJNFFYDFQUJPO terminates program execution.

)PXEPZPVLOPXXIFUIFSBOFYDFQUJPOJTDIFDLFEPSVODIFDLFE :PVDBO DPOTVMUUIFEPDVNFOUBUJPOGPSUIF+BWB$MBTT-JCSBSZUPMFBSOUIFFYDFQUJPOT base class and from that deduce whether it is checked or unchecked. Figure 9.1 shows the hierarchy of the predefined exception classes. The class Exception JTUIFCBTFDMBTTPGBMMFYDFQUJPOT&WFSZFYDFQUJPODMBTTJTBEFTDFOEBOUPGUIF class Exception—that is, it is derived either directly from the class Exception or from a class that ultimately is derived from the class Exception. Classes of unchecked exceptions are derived from the class RuntimeException. All other exception classes are of checked exceptions that must be caught.

Some exceptions do not need to be caught

All exception classes are derived from the predefined class Exception.

FIGURE 9.1 Hierarchy of the Predefined Exception Classes Object

Exception

RuntimeException Throwable

Error

AssertionError We discuss

the class Error in the next section.

Class for an unchecked exception

Class for a checked exception

686 CHAPTER 9 / Exception Handling

You need not worry too much about which exceptions you do and do not need to catch or declare in a throws clause. If you fail to account for some exception that Java requires you to handle, the compiler will tell you about it.

You can then either catch it or add it to a throws clause.

RECAP Kinds of Exceptions

Every exception class is a descendant class of the class Exception. RuntimeException is derived from Exception, and classes derived fromRuntimeException or any of its descendants represent unchecked exceptions. Such exceptions do not need to be caught or declared in a throws clause of a method’s heading. All other exceptions are checked and must be either caught or declared in a throws clause.

Errors

Anerror is an object of the class Error, which is derived from Throwable, as Figure 9.1 indicates. Note that Throwable is also the base class of Exception. Technically speaking, the class Error and its descendant classes are not considered exception classes, because they are not descendants of the class Exception. To us, however, they look like exceptions. Objects of the class Error are similar to unchecked exceptions in that we need not catch or declare them in a throwsDMBVTFFWFOUIPVHIZPVDPVME&SSPSTBSFNPSFPSMFTTCFZPOEZPVS control. For example, an OutOfMemoryError occurs if your program has run out of memory. This means that you must either revise your program to make it more efficient in its use of memory, change a setting to let Java access more memory, or buy more memory for your computer. Adding a catch block will not help in this case.

When we discussed the assert operator and assertion checking in Chapter 4, we said that if your program contains an assertion check and the assertion check fails, your program will end with an error message. What actually happens is that an AssertionError occurs. As the name suggests, the classAssertionError is derived from the class Error.

An error is not an exception, but is similar to one

RECAP The ClassError

Errors are objects of the class Error that are generated when certain abnormal conditions occur. Most programs should not catch them or declare them in a throws clause. Errors are technically not exceptions, even though they look like them.

Multiple Throws and Catches

A try block can potentially throw any number of exceptions, which can CF PG EJGGFSFOU UZQFT &BDIcatch block can catch exceptions of only one type, but you can catch exceptions of different types by placing more than one catch block after a try block. For example, the program in Listing 9.8

Atry block may be followed by severalcatch blocks

LISTING 9.8 Catching Multiple Exceptions (part 1 of 2)

import java.util.Scanner;

public class TwoCatchesDemo {

public static void main(String[] args) {

try {

System.out.println("Enter number of widgets " + "produced:");

Scanner keyboard = new Scanner(System.in);

int widgets = keyboard.nextInt();

if (widgets < 0)

throw new NegativeNumberException("widgets");

System.out.println("How many were defective?");

int defective = keyboard.nextInt();

if (defective < 0)

throw new NegativeNumberException("defective " +

"widgets");

double ratio = exceptionalDivision(widgets, defective);

System.out.println("One in every " + ratio +

" widgets is defective.");

}

catch(DivideByZeroException e) {

System.out.println("Congratulations! A perfect " + "record!");

}

catch(NegativeNumberException e) {

System.out.println("Cannot have a negative number of " + e.getMessage());

}

(continued) This is just an ex ample of handling exceptions using two catch blocks.

688 CHAPTER 9 / Exception Handling

LISTING 9.8 Catching Multiple Exceptions (part 2 of 2) System.out.println("End of program.");

}

public static double exceptionalDivision(double numerator, double denominator) throws DivideByZeroException {

if (denominator == 0)

throw new DivideByZeroException();

return numerator / denominator;

} }

Sample Screen Output 1

Enter number of widgets produced:

1000

How many were defective?

500

One in every 2.0 widgets is defective.

End of program.

Sample Screen Output 2

Enter number of widgets produced:

—10

Cannot have a negative number of widgets End of program.

Sample Screen Output 3

Enter number of widgets produced:

1000

How many were defective?

0

Congratulations! A perfect record!

End of program.

has two catch blocks after its try block. One catch block is for exceptions of type DivideByZeroException—defined earlier in Listing 9.5—and the second is for exceptions of type NegativeNumberException, which is defined in Listing 9.9.

LISTING 9.9 The Class NegativeNumberException public class NegativeNumberException extends Exception {

public NegativeNumberException() {

super("Negative Number Exception!");

}

public NegativeNumberException(String message) {

super(message);

} }

PROGRAMMING TIP Catch the More Specific Exception First

When catching multiple exceptions, the order of the catch blocks can be important. When an exception is thrown in a try block, the catch blocks are examined in order of appearance. The first block that matches the type of the exception thrown is the one that executes. Thus, the following ordering of catch blocks would not be good:

catch(Exception e) //This catch block should not be first.

{ ...

}

catch(DivideByZeroException e) {

...

}

The second catch block can never be reached.

With this ordering, the catch block for DivideByZeroException would never be used, because all exceptions are caught by the first catch block. Fortunately, the compiler will probably warn you about this problem.

The correct ordering is to reverse the catch blocks so that the more specific exception comes before its parent exception class, as shown in the following code:

catch(DivideByZeroException e) {

...

}

catch(Exception e) {

...

} ■

The order of catch blocks matters

690 CHAPTER 9 / Exception Handling

PROGRAMMING TIP User Input

When your program reads input data entered by the user of your program, ZPVMJLFMZXJMMOFFEUPEFBMXJUIFYDFQUJPOT6TFSTDBOUZQFBMNPTUBOZUIJOHBT

input, unintentionally or not! ■

PROGRAMMING TIP Exception Handling and Information Hiding

You know that a method invocation can cause an exception that is declared JO UIF NFUIPETthrows clause. Any time an exception is thrown, regardless of whether you write a throw statement or call a method, you handle it in the exact same way: It is either caught in a catch block or declared in another throws clause. When analyzing a method invocation that might throw an exception, do not think about where in the method definition the throw statement is located. It does not matter how the exception is thrown. All that matters is that the method invocation might throw an exception. The exception is handled in the same way no matter what happens inside the

method. ■

S E L F - T E S T Q U E S T I O N S

24. Correct the following method definition by adding a suitable throws clause:

public void doStuff(int n) {

if (n < 0)

throw new Exception("Negative number.");

}

25. What happens if you invoke a method and it throws a checked exception that it does not catch?

26. Consider an invocation of method A. Suppose that method A calls method B, and method B calls method C. If method C throws an exception that it does not catch itself, where might the exception be caught? In B? In A? Outside of A?

27. What output will be produced by the following code? The definition of the class NegativeNumberException is given in the preceding material, but you do not need to look at it to answer this question.

try {

int n = 7;

if (n > 0)

throw new Exception();

else if (n < 0)

throw new NegativeNumberException();

else

System.out.println("Hello!");

}

catch(NegativeNumberException e) {

System.out.println("First catch.");

}

catch(Exception e) {

System.out.println("Second catch");

}

System.out.println("End of code");

3FQFBU4FMG5FTU2VFTUJPOCVUDIBOHFUIFWBMVFPGOGSPNUP¦

3FQFBU4FMG5FTU2VFTUJPOCVUDIBOHFUIFWBMVFPGn from 7 to 0.

30. What output is produced by the following program?

public class Question30 {

public static void main(String[] args) {

Question30 object = new Question30();

try {

System.out.println("Trying");

object.sampleMethod();

System.out.println("Trying after call.");

}

catch(Exception e) {

System.out.println("Catching");

System.out.println(e.getMessage());

} }

public void sampleMethod() throws Exception {

System.out.println("Starting sampleMethod.");

throw new Exception("From sampleMethod with love.");

} }

692 CHAPTER 9 / Exception Handling

PROGRAMMING TIP Where to Throw an Exception

Thus far, we have used some very simple code to illustrate the basic concepts PG FYDFQUJPO IBOEMJOH )PXFWFS PVS FYBNQMFT XFSF VOSFBMJTUJDBMMZ TJNQMF *O general, you should separate throwing an exception and catching the exception into separate methods. For example, one method might have the following form:

public void methodA() throws MyException {

...

throw new MyException("Blah Blah Blah");

...

}

and some other method—perhaps even in some other class—might be public void methodB()

{ ...

try { ...

methodA();

...

}

catch(MyException e) {

... //Deal with the exception.

} ...

}

FAQ When should my code throw an exception?

The use of a throw statement should be reserved for cases in which it is unavoidable. If you are tempted to include a throw statement, think about how you might write your program or class definition without thisthrow statement. If you can think of an alternative that produces reasonable code, you probably should not throw an exception. But if the way to deal with an exceptional condition depends on how and where a method is invoked, the best approach is to let the programmer who invokes the method handle the exception. In all other situations, it is preferable to avoid throwing exceptions.

Predefined methods often leave exception handling to the programmer invoking the method. When you learn about a predefined method, you may be told that it throws exceptions of certain kinds. You, as the programmer who uses the predefined method, are then expected to handle any exception thrown by the method.

5IFSFBTPOGPSUIJTJTSFMBUFEUPUIFQSFWJPVT'"2POXIFOZPVTIPVMEUISPX an exception. If a method knows how to deal with a certain situation, it likely should do so without throwing an exception. If an exception is thrown by some code within a method—for example, if your method invokes another method that throws an exception—handle it if you can. Otherwise, declare the exception in a throws clause in your method, and let a different method

contain the catch block. ■

GOTCHA Nested try-catchBlocks

Although you can place a try block and its subsequent catch blocks inside a larger try block or inside a larger catch block, doing so is rarely useful. If you are tempted to nest these blocks, you should at least consider whether there is another way to organize your code. For example, you might eliminate one or more try blocks completely, or you could place the inner try-catch blocks inside a method definition and invoke that method within the outer try block or catch block. It is almost always better to avoid nested try-catch blocks.

Suppose, however, that you do use nested try-catch blocks. If you place atry block and its subsequent catch blocks inside a larger try block, and an exception is thrown in the inner try block but is not caught in the inner catch blocks, the exception is thrown to the outer try block for processing and might be caught in one of the outer catch blocks. If you place a try block and its subsequent catch blocks inside a larger catch block, you will need to use different names for the catchCMPDLQBSBNFUFSTJOUIFJOOFSBOEPVUFS blocks, respectively. After all, try blocks and catch blocks are blocks, so you need to remember how Java handles nested blocks of any kind. ■

The finally Block

You can add a finally block after a sequence of catch blocks. The code in the finally block is executed whether or not an exception is thrown. This block gives you an opportunity to clean up any loose ends that linger as a result of the exception.

The general syntax is as follows:

try { ...

}

Catch_Block(s) finally

{

Some_Code //Always executed.

}

VideoNote Using a throws clause

Afinally block always executes

Một phần của tài liệu java an introductioan to problem solving and programming 6th edition (Trang 717 - 743)

Tải bản đầy đủ (PDF)

(987 trang)