java中的异常--Exceptions in Java-- 第五部分

简介:  TemperatureException        at VirtualPerson.drinkCoffee(VirtualPerson.java:20)        at VirtualCafe.

 TemperatureException
        at VirtualPerson.drinkCoffee(VirtualPerson.java:20)
        at VirtualCafe.serveCustomer(VirtualCafe.java:9)
        at Example7.main(Example7.java:12)

                    


The throws clause
As you may have guessed from the examples above, the Java language requires that a method declare in a throws clause the exceptions that it may throw. A method's throws clause indicates to client programmers what exceptions they may have to deal with when they invoke the method.

For example, the drinkCoffee() method of class VirtualPerson, shown below, declares three exceptions in its throws clause: TooColdException, TemperatureException, and UnusualTasteException. These are the three exceptions that the method throws but doesn't catch. The method also may throw TooHotException, but this exception doesn't appear in the throws clause because drinkCoffee() catches and handles it internally. Only exceptions that will cause a method to complete abruptly should appear in its throws clause.

                        // In Source Packet in file except/ex7/VirtualPerson.java
class VirtualPerson {
    public void drinkCoffee(CoffeeCup cup) throws TooColdException,
        TemperatureException, UnusualTasteException {
        try {
            int i = (int) (Math.random() * 4.0);
            switch (i) {
            case 0:
                throw new TooHotException();
            case 1:
                throw new TooColdException();
            case 2:
                throw new UnusualTasteException();
            default:
                throw new TemperatureException();
            }
        }
        catch (TooHotException e) {
            System.out.println("This coffee is too hot.");
            // Customer will wait until it cools to an
            // acceptable temperature.
        }
    }
    //...
}

                    


In the drinkCoffee() method above, each exception declared in the throws clause is explicitly thrown by the method via a throw statement. This is one of two ways a method can complete abruptly. The other way is by invoking another method that completes abruptly.

An example of this is VirtualCafe's serveCustomer() method, shown below, that invokes VirtualPerson's drinkCoffee() method. The serveCustomer() method contains no throw statements, but it does declare two exceptions in its throws clause: TemperatureException and UnusualTasteException. These are two of three exceptions that may be thrown by drinkCoffee(), which serveCustomer() invokes. The third exception, TooColdException, doesn't appear in the throws clause because serveCustomer() catches and handles it internally. Only those exceptions that will cause the serveCustomer() method to complete abruptly appear in its throws clause.

                        // In Source Packet in file except/ex7/VirtualCafe.java
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup)throws TemperatureException,
        UnusualTasteException {
        try {
            cust.drinkCoffee(cup);
        }
        catch (TooColdException e) {
            System.out.println("This coffee is too cold.");
            // Add more hot coffee...
        }
    }
}

                    


Although a throws clause lists exceptions that may cause a method to complete abruptly, the list is not necessarily complete. Not everything that can be thrown by a method need be put in a throws clause.

Checked vs. unchecked exceptions
There are two kinds of exceptions in Java, checked and unchecked, and only checked exceptions need appear in throws clauses. The general rule is: Any checked exceptions that may be thrown in a method must either be caught or declared in the method's throws clause. Checked exceptions are so called because both the Java compiler and the Java virtual machine check to make sure this rule is obeyed.

Whether or not an exception is "checked" is determined by its position in the hierarchy of throwable classes. Figure 4 shows that some parts of the Throwable family tree contain checked exceptions while other parts contain unchecked exceptions. To create a new checked exception, you simply extend another checked exception. All throwables that are subclasses of Exception, but not subclasses of RuntimeException are checked exceptions.

Figure 4. Checked and unchecked throwables

The conceptual difference between checked and unchecked exceptions is that checked exceptions signal abnormal conditions that you want client programmers to deal with. For instance, because the drinkCoffee() method allocates memory with the new operator, it could potentially complete abruptly by throwing an OutOfMemoryError. This is not a checked exception, because it's not a subclass of Exception. It's a subclass of Error. Conceptually, OutOfMemoryError isn't a checked exception because you don't want client programmers to have to deal directly with the fact that drinkCoffee() could complete abruptly due to low memory.

When you place an exception in a throws clause, it forces client programmers who invoke your method to deal with the exception, either by catching it or by declaring it in their own throws clause. If they don't deal with the exception in one of these two ways, their classes won't compile. For example, because the drinkCoffee() method declares three exceptions in its throws clause, the serveCustomer() method, which invokes drinkCoffee(), has to deal with those three exceptions. In this case, serveCustomer() catches one exception, TooColdException, but not the other two. If serveCustomer() hadn't declared in its throws clause the other two exceptions, TemperatureException and UnusualTasteException, the VirtualCafe class would not have compiled.

Most unchecked throwables declared in java.lang (subclasses of Error and RuntimeException) are problems that would be detected by the Java virtual machine. Errors usually signal abnormal conditions that you wouldn't want a program to handle. Problems with linking, such as NoClassDefFoundError, or memory, such as StackOverflowError, could happen just about anywhere in a program. In the rare cases in which they happen, it is usually reasonable that the thread terminate.

Although most runtime exceptions (members of the RuntimeException family) also are thrown by the Java virtual machine itself, they usually are more an indication of software bugs. Problems with arrays, such as ArrayIndexOutOfBoundsException, or passed parameters, such as IllegalArgumentException, also could happen just about anywhere in a program. When exceptions like these are thrown, you'll want to fix the bugs that caused them to be thrown. You won't, however, want to force client programmers to wrap every invocation of a method that uses arrays with a catch clause for ArrayIndexOutOfBoundsException.

You can throw and catch unchecked exceptions just like checked exceptions, but the Java Language Specification advises against throwing errors. It is intended that errors be thrown only by the Java runtime. You may, however, reasonably throw runtime exceptions. You can throw a runtime exception declared in java.lang or declare your own subclasses of RuntimeException.

To decide whether to throw a checked exception or an unchecked runtime exception, you must look at the abnormal condition you are signalling. If you are throwing an exception to indicate an improper use of your class, you are signalling a software bug. The class of exception you throw probably should descend from RuntimeException, which will make it unchecked. Otherwise, if you are throwing an exception to indicate not a software bug but an abnormal condition that client programmers should deal with every time they use your method, your exception should be checked.

The finally clause
Once a Java virtual machine has begun to execute a block of code -- the statements between two matching curly braces -- it can exit that block in any of several ways. It could, for example, simply execute past the closing curly brace. It could encounter a break, continue, or return statement that causes it to jump out of the block from somewhere in the middle. Or, if an exception is thrown that isn't caught inside the block, it could exit the block while searching for a catch clause.

Given that a block can be exited in many ways, it is important to be able to ensure that something happens upon exiting a block, no matter how the block is exited. For example, if you open a file in a method, you may want to ensure the file gets closed no matter how the method completes. In Java, you express such a desire with a finally clause.

To use a finally clause, you simply: (1) Enclose the code that has multiple exit points in a try block; and (2) place the code that must be executed when the try block is exited in a finally clause.

Here's an example:

                        try {
    // Block of code with multiple exit points
}
finally {
    // Block of code that must always be executed when the try block
    // is exited, no matter how the try block is exited
}

                    


At least one clause, either catch or finally, must be associated with each try block. If you have both catch clauses and a finally clause with the same try block, you must put the finally clause after all the catch clauses, as in:

                        // In Source Packet in file except/ex8/VirtualPerson.java
class VirtualPerson {
    public void drinkCoffee(CoffeeCup cup) {
        try {
            int i = (int) (Math.random() * 4.0);
            switch (i) {
            case 0:
                throw new TooHotException();
            case 1:
                throw new TooColdException();
            case 2:
                throw new UnusualTasteException();
            default:
                System.out.println("This coffee is great!");
            }
        }
        catch (TooHotException e) {
            System.out.println("This coffee is too hot.");
        }
        catch (TooColdException e) {
            System.out.println("This coffee is too cold.");
        }
        catch (UnusualTasteException e) {
            System.out.println("This coffee is too strong.");
        }
        finally {
            System.out.println("Can I please have another cup?");
        }
    }
    //...
}

                    


If during execution of the code within a try block, an exception is thrown that is handled by a catch clause associated with the try block, the finally clause will be executed after the catch clause. For example, if a TooColdException exception is thrown during execution of the try block above, the program would print the following:

                        This coffee is too cold.
Can I please have another cup?

                    


If an exception is thrown that is not handled by a catch clause associated with the try block, the finally clause is still executed. The Java virtual machine will execute the code of the finally clause before it continues searching elsewhere for an appropriate catch clause. There is no way to leave a try block without executing the code of its finally clause.

You can do anything inside a finally clause that you can do elsewhere, including executing break, continue, or return statements, or throwing exceptions. Such actions inside a finally clause, however, can have some surprising effects. For example, consider a finally clause that is entered because of an uncaught exception. If the finally clause executes a return, the method would complete normally via the return, not abruptly by throwing the exception. The exception would have in effect been handled by the finally clause instead of a catch clause.

As another example, consider a finally clause that is entered because a return true; statement was executed inside the try block. If the finally clause executes a return false; statement, the method will return false.

Conclusion
Java goes to great lengths to help you deal with error conditions. Java's exception mechanisms give you a structured way to perform a go-to from the place where an error occurs to the code that knows how to handle the error. These mechanisms also enable you to force client programmers (those who use your code by calling your methods) to deal with the possibility of an error condition encountered by your code. But Java's mechanisms do not force you to design your programs to take advantage of these capabilities. In the end, if you want your programs to handle error conditions in a structured, methodical way, you must use the exception mechanisms correctly.

For advice on how to put the exception mechanisms described in this article to use in your programs and designs, see this month's Design Techniques column, "Designing with exceptions."

Author Bio
Bill Venners has been writing software professionally for 12 years. Based in Silicon Valley, he provides software consulting and training services under the name Artima Software Company. Over the years he has developed software for the consumer electronics, education, semiconductor, and life insurance industries. He has programmed in many languages on many platforms: assembly language on various microprocessors, C on Unix, C++ on Windows, Java on the Web. He is author of the book: Inside the Java Virtual Machine, published by McGraw-Hill.

 

目录
相关文章
|
1月前
|
Java
Java中的异常链:从根源到解决方案
Java中的异常链:从根源到解决方案
35 0
|
1月前
|
存储 监控 Java
Java认识异常(超级详细)
Java认识异常(超级详细)
|
3月前
|
Java 程序员 数据库连接
JAVA中的异常
Throwable Error Exception 编译时异常 运行时异常 异常的处理 try-catch捕获并处理 finally throw throws 自定义异常类
26 0
|
28天前
|
SQL Java
java中的异常
java中的异常
9 1
|
28天前
|
Java 程序员 编译器
Java中异常
Java中异常
12 0
|
28天前
|
Java 程序员 编译器
Java中的异常
Java中的异常
9 0
|
28天前
|
Java
Java异常的抛出
Java异常的抛出
8 0
|
1月前
|
Java 索引
JAVA异常类及其主要方法
JAVA异常类及其主要方法
28 3
|
1月前
|
Java
JAVA异常概述
JAVA异常概述
8 1
|
1月前
|
Java 程序员 数据安全/隐私保护
Java中的异常语法知识居然这么好玩!后悔没有早点学习
Java中的异常语法知识居然这么好玩!后悔没有早点学习
32 1