`
leonzhx
  • 浏览: 766715 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Chapter 12. Error Handling with Exceptions -- Thinking in Java

阅读更多

1) An exceptional condition is a problem that prevents the continuation of the current method or scope. It’s important to distinguish an exceptional condition from a normal problem, in which you have enough information in the current context to somehow cope with the difficulty. With an exceptional condition, you cannot continue processing because you don’t have the information necessary to deal with the problem in the current context. All you can do is jump out of the current context and relegate that problem to a higher context. This is what happens when you throw an exception.

 

2) When you throw an exception, several things happen. First, the exception object is created in the same way that any Java object is created: on the heap, with new. Then the current path of execution (the one you couldn’t continue) is stopped and the reference for the exception object is ejected from the current context. At this point the exception-handling mechanism takes over and begins to look for an appropriate place to continue executing the program. This appropriate place is the exception handler, whose job is to recover from the problem so the program can either try another tack or just continue.

 

3) There are two constructors in all standard exceptions: The first is the default constructor, and the second takes a string argument so that you can place pertinent information in the exception.

 

4) The keyword throw produces a number of interesting results. After creating an exception object with new, you give the resulting reference to throw. The object is, in effect, "returned" from the method, even though that object type isn’t normally what the method is designed to return. You can also exit from ordinary scopes by throwing an exception. In either case, an exception object is returned, and the method or scope exits. You end up in an appropriate exception handler that might be far away—many levels on the call stack—from where the exception was thrown.

 

5) You can throw any type of Throwable, which is the exception root class.

 

6) A guarded region is a section of code that might produce exceptions and is followed by the code to handle those exceptions. 

 

7) If you don’t want a throw to exit the method, you can set up a special block within that method to capture the exception. This is called the try block because you "try" your various method calls there. The try block is an ordinary scope preceded by the keyword try.

 

8) With exception handling, you put everything in a try block and capture all the exceptions in one place. This means your code is much easier to write and read because the goal of the code is not confused with the error checking.

 

9) Thrown exception must end up someplace. This "place" is the exception handler, and there’s one for every exception type you want to catch. Exception handlers immediately follow the try block and are denoted by the keyword catch:

try {
// Code that might generate exceptions
} catch(Type1 id1)|{
// Handle exceptions of Type1
} catch(Type2 id2) {
// Handle exceptions of Type2
} catch(Type3 id3) {
// Handle exceptions of Type3
}

 

Each catch clause (exception handler) is like a little method that takes one and only one argument of a particular type.

 

10) If an exception is thrown, the exception-handling mechanism goes hunting for the first handler with an argument that matches the type of the exception. Then it enters that catch clause, and the exception is considered handled. 

 

11) You may want to send error output to the standard error stream by writing to System.err. This is usually a better place to send error information than System.out, which may be redirected.

 

12) One of the Throwable (from which Exception is inherited) methods is called: printStackTrace( ). This method produces information about the sequence of methods that were called to get to the point where the exception happened. ( if no parameter is sent to it , the information will go to standard error stream )

 

13) The static Logger.getLogger(String ) method creates a Logger object associated with the string argument (usually the name of the package and class that the errors are about) which sends its output to System.err.

 

14) Java provides syntax (and forces you to use that syntax) to allow you to politely tell the client programmer what exceptions this method throws, so the client programmer can handle them. This is the exception specification and it’s part of the method declaration, appearing after the argument list. The exception specification uses an additional keyword, throws, followed by a list of all the potential exception types.

 

15) You can’t lie about an exception specification. If the code within your method causes exceptions, but your method doesn’t handle them, the compiler will detect this and tell you that you must either handle the exception or indicate with an exception specification that it may be thrown from your method.

 

16) There is one place you can lie: You can claim to throw an exception that you really don’t. This has the beneficial effect of being a placeholder for that exception, so you can actually start throwing the exception later without requiring changes to existing code. It’s also important for creating abstract base classes and interfaces whose derived classes or implementations may need to throw exceptions.

 

17) Exceptions that are checked and enforced at compile time are called checked exceptions.

 

18) It is possible to create a handler that catches any type of exception. You do this by catching the base-class exception type Exception (there are other types of base exceptions, but Exception is the base that’s pertinent to virtually all programming activities)

 

19)  The method of Throwable:
String getMessage( ) , String getLocalizedMessage( )
Gets the detail message, or a message adjusted for this particular locale.
String toString( )
Returns a short description of the Throwable, including the detail message if there is one.
void printStackTrace( ) , void printStackTrace(PrintStream), void printStackTrace(java.io.PrintWriter)
Prints the Throwable and the Throwable’s call stack trace. The call stack shows the sequence of method calls that brought you to the point at which the exception was thrown. The first version prints to standard error, the second and third print to a stream of your choice.
Throwable fillInStackTrace( )
Records information within this Throwable object about the current state of the stack frames. Useful when an application is rethrowing an error or exception.

Commented by Sean: it will override the original stack trace information.

 

20) getClass( ) of Object returns an object representing the class of this object. You can in turn query this Class object for its name with getName( ), which includes package information, or getSimpleName( ), which produces the class name alone.

 

21) Throwable.getStackTrace( ) returns an array of StackTraceElement, each representing one stack frame. Element zero is the top of the stack, and is the last method invocation in the sequence (the point this Throwable was created instead of thrown). The last element of the array and the bottom of the stack is the first method invocation in the sequence.

 

22) Sometimes you’ll want to rethrow the exception that you just caught, particularly when you use Exception to catch any exception. Rethrowing an exception causes it to go to the exception handlers in the next higher context. Any further catch clauses for the same try block are still ignored. If you simply rethrow the current exception, the information that you print about that exception in printStackTrace( ) will pertain to the exception’s origin, not the place where you rethrow it. If you want to install new stack trace information, you can do so by calling fillInStackTrace( ), which returns a Throwable object that it creates by stuffing the current stack information into the old exception object. The line where fillInStackTrace( ) is called becomes the new point of origin of the exception.

 

23) Often you want to catch one exception and throw another, but still keep the information about the originating exception—this is called exception chaining. All Throwable subclasses have the option to take a cause object in their constructor. The cause is intended to be the originating exception, and by passing it in you maintain the stack trace back to its origin, even though you’re creating and throwing a new exception.

 

24) It’s interesting to note that the only Throwable subclasses that provide the cause argument in the constructor are the three fundamental exception classes Error (used by the JVM to report system errors), Exception, and RuntimeException. If you want to chain any other exception types, you do it through the initCause( ) method rather than the constructor.

 

25) There are two general types of Throwable objects ("types of" = "inherited from"). Error represents compile-time and system errors that you don’t worry about catching (except in very special cases). Exception is the basic type that can be thrown from any of the standard Java library class methods and from your methods and runtime accidents. So the Java programmer’s base type of interest is usually Exception.

 

26) The exceptions are not all defined in java.lang; some are created to support other libraries such as util, net, and io, which you can see from their full class names or what they are inherited from.

 

27) There’s a whole group of exception types that are always thrown automatically by Java and you don’t need to include them in your exception specifications. They’re all grouped together by putting them under a single base class called RuntimeException. You never need to write an exception specification saying that a method might throw a RuntimeException (or any type inherited from RuntimeException), because they are unchecked exceptions. If a RuntimeException gets all the way out to main( ) without being caught, printStackTrace( ) is called for that exception as the program exits.

 

28) RuntimeException is designed to handle those pesky runtime errors that will occur because of forces outside your code’s control, but it’s also essential for certain types of programming bugs that the compiler cannot detect.

 

29) There’s often some piece of code that you want to execute whether or not an exception is thrown within a try block. This usually pertains to some operation other than memory recovery (since that’s taken care of by the garbage collector). To achieve this effect, you use a finally clause at the end of all the exception handlers.

 

30) The finally statement will also be executed in situations in which break, continue and even return statements are involved. Note that, along with the labeled break and labeled continue, finally eliminates the need for a goto statement in Java.

LABEL:
try {
   ...
   break LABEL;
}  finally {
   ...
}

 

 

31) An Exception thrown from finally block will replace the Exception thrown from its corresponding try block and using return inside the finally block will silence any thrown exception.

 

32) When you override a method, you can throw only the exceptions that have been specified in the base-class version of the method. This is a useful restriction, since it means that code that works with the base class will automatically work with any object derived from the base class (a fundamental OOP concept, of course), including exceptions. It's OK to add new exceptions for constructors, but you must deal with (add the corresponding exception declaration) the base constructor exceptions. Overridden methods can throw inherited exceptions. A derived-class constructor cannot catch exceptions thrown by its base-class constructor.( because base class constructor call must be the first statement ) A derived-class version of a method may choose not to throw any exceptions, even if the base-class version does.

 

33) Right after you create an object that requires cleanup, begin a try-finally. Objects with constructors that cannot fail can be grouped together for both construction and cleanup.

 

34) When an exception is thrown, the exception-handling system looks through the "nearest" handlers in the order they are written. When it finds a match, the exception is considered handled, and no further searching occurs. A derived-class object of exception will match a handler for the base class exception.

 

35) In the past, I have been a strong believer that both checked exceptions and static type checking were essential to robust program development. However, both anecdotal and direct experience with languages that are more dynamic than static has led me to think that the great benefits actually come from:

    a. A unified error-reporting model via exceptions, regardless of whether the programmer is forced by the compiler to handle them.
    b. Type checking, regardless of when it takes place. That is, as long as proper use of a type is enforced, it often doesn’t matter if it happens at compile time or run time.

 

36) In simple programs, the easiest way to preserve the exceptions without writing a lot of code is to pass them out of main( ) to the console.

 

38) Wrapping a checked exception inside a RuntimeException by passing it to the RuntimeException constructor seems to be an ideal solution if you want to "turn off the checked exception—you don’t swallow it, and you don’t have to put it in your method’s exception specification, but because of exception chaining you don’t lose any information from the original exception.

 

39) Exception guidelines -- Use exceptions to:
    a. Handle problems at the appropriate level. (Avoid catching exceptions unless you know what to do with them.)
    b. Fix the problem and call the method that caused the exception again.
    c. Patch things up and continue without retrying the method.
    d. Calculate some alternative result instead of what the method was supposed to produce.
    e. Do whatever you can in the current context and rethrow the same exception to a higher context.

    f.  Do whatever you can in the current context and throw a different exception to a higher context.

    g. Terminate the program.
    h. Simplify. (If your exception scheme makes things more complicated, then it is painful and annoying to use.)
    i. Make your library and program safer. (This is a short-term investment for debugging, and a long-term investment for application robustness.)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics