{Effective Java} Chap 9 Exceptions

来源:互联网 发布:木庄网络博客整站源码 编辑:程序博客网 时间:2024/06/05 03:55



When used properly, exceptions can improve a program's readability, reliability and maintainability.

Item 57: Use exceptions only for exceptional conditions

Exceptions are to be used only for exceptional conditions, they should never be used for orinary control flow.

A well-designed API must not force its clients to use exceptions for ordinary control flow. 

Guidelines that help choose between a state-testing method and a distinguished return value:

If an object is to be accessed concurrently without external synchronization or is subject to externally induced state transitions, you must use return value. Because the object's state could change in the interval between the invocation of a state-testing method and its state-dependent method.

If a state-testing method duplicate the work, we should use return value.

In other conditions, use state-testing methods.


In summary, exceptions are designed for use in exceptional conditions. Don't use them for ordinary control flow and dont write APIs that force others to do so.



Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors

Checked Exception, Runtime exceptions and error (both are throwables and shouldn't be caught).

Most runtime exceptions indicate precondition violations. 

JVM throws errors such as resource deficiencies, invariant failures and other conditions that make it impossible to continue execution.

All of the unchecked throwables you implement should subclass RuntimeException.


To summarize, because checked exceptions generally indicate recoverable conditions, it's especially important for such exceptions to provide methods that furnish information that could help the caller to recover. 



Item 59: Avoid unnecessary use of checked exceptions

If the programmer using the API can do no better, an unchecked exception would be more appropriate. 

If it is the sole checked exception thrown by a method, the burden is higher.


Item 60: Favor the use of standard exceptions

Experts strive for a high degree of code reuse.

Reusing preexisting exceptions has several benefits. 

makes your API easier to learn and use, read. Fewer exception classes mean a smaller memory footprint and less time spent loading classes.


IllegalArgumentException --- checks whether arguments values are valid. Non-null parameter value is inappropriate.

IllegalStateException --- thrown if the invocation is illegal because of the state of the receiving object. 

ConcurrentModificationException --- used by a single thread or with external synchronization detects that it is being concurrently modified. 

UnsupportedOperationException --- checks the attempted operation.

NullPointerException --- Parameter value is null where prohibited.

IndexOutOfBoundsException --- index parameter value is out of range.



Item 61: Throw exceptions appropriate to the abstraction

Higher layers should catch lower-level exceptions and in their place, throw exceptions that can be explained in terms of the higher-level abstraction.

Exception translation / chaining

/** * Returns the element at the specified position in this list. *  * @thows IndexOutOfBoundsException if the index is out of range. *        {@code index < 0 || index >= size()} */public E get(int index){ListIterator<E> i = listIterator<index>;try {return i.next;} catch (NoSuchElementException e) {throw new IndexOutOfBoundsException("Index: " + index);}}


While exception translation is superior to mindless propagation of exceptions from lower layers, it should not be overused.

//Exception Chainingtry{... // Use lower-level abstraction to do our bidding}catch(LowerLevelException cause){throw new HigherLevelException(cause);}//Exception with chaining-aware constructorclass HigherLevelException extends Exception{HigherLevelException(Throwable cause) {super(cause);}}



In summary, if it isn't feasible to prevent or to handle exceptions from lower layers, use exception translation, unless the lower-level method happens to guarantee that all of its exceptions are appropriate to the higher level. Chaining provides the best of both worlds: it allows you to throw an appropriate higher-level exception, while capturing the underlying cause for failure analysis.


Item 62: Document all exceptions thrown by each method 

Always declare checked exceptions individually, and document precisely the conditions under which each one is thrown using the Javadoc @throws tag.

Never declare a method that throws Exception, which obscures other exceptions that may be thrown.

Documenting its unchecked exceptions is the best way to describe preconditions.

Use Javadoc @thorws tag to document each unchecked exception that a method can throw, but do not use the throws keyword to include unchecked exceptions in the method declaration.

If an exception is thrown by many methods in a class for the same reason, it is acceptable to document the exception in the class's documentation comment. E.g NullPointerException


In summary, document every exception that can be thrown by each method. 



Item 63: Include failure-capture information in detail messages

To capture the failure, the detail message of an exception should contain the values of all parameters and fields that contributed to the exception.

The detail message of an exception should not be confused with a user-level error message, which must be intelligible to end users.

Require failure information in their constructors instead of a string detail message.

E.g

/** * Construct an IndexOutOfBoundsException. *  * @param lowerBound the lowest legal index value. * @param upperBound the highest legal index value plus one. * @param index the actual index value. */public IndexOutOfBoundsException(int lowerBound, int upperBound, int index){//Generate a detail message that captures the failuresuper("Lower bound: " + lowerBound + ", Upper bound: " + upperBound + ", Index: " + index);//Save failure information for programmatic accessthis.lowerBound = lowerBound;this.upperBound = upperBound;this.index = index;}



It is important to provide accessor methods on checked exceptions than on unchecked exception.



Item 64: Strive for failure atomicity

Generally speaking, a failed method invocation should leave the object in the state that it was prior to the invocation.

1. design immutable objects, whose state is consistent when it is created and can't be modified thereafter.

Check parameters for validity before performing the operation.

2. order the computation so that any part that may fail takes place before any part that modifies the object. 

3. write recovery code that intercepts a failure, most used for durable (disk-based) data structures.

4. perform the operation on a temporary copy and substitude original one once the operation is complete.


public Object pop(){if(size == 0)throw new EmptyStackException();Object result = elements[-- size];elements[size] == null;  //Eliminate obsolete referencereturn result;}



As a rule, errors are unrecoverable, and methods need not even attempt to preserve failure atomicity when throwing errors.

As a rule, any generated exception that is part of a method's specification should leave the object in the same state it was in prior to the method invocation. If violated, need API documentation the state.



Item 65: Don't ignore exceptions

An empty catch block defeats the purpose of exceptions.

At the every least, the catch block should contain a comment explaining why it is appropriate to ignore the exception.

Properly handling an exception can avert failure entirely.



0 0
原创粉丝点击