代码改变世界

Effective Java 61 Throw exceptions appropriate to the abstraction

2014-04-25 22:38  小郝(Kaibo Hao)  阅读(366)  评论(0编辑  收藏  举报

Exception translation: 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

try {

// Use lower-level abstraction to do our bidding

...

} catch(LowerLevelException e) {

throw new HigherLevelException(...);

}

Example

/**

* Returns the element at the specified position in this list.

* @throws 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);

}

}

ExceptionChain: The lower-level exception (the cause) is passed to the higher-level exception, which provides an accessor method (Throwable.getCause ) to retrieve the lower-level exception:

// Exception Chaining

try {

... // Use lower-level abstraction to do our bidding

} catch (LowerLevelException cause) {

throw new HigherLevelException( cause);

}

// Exception with chaining-aware constructor

class HigherLevelException extends Exception {

HigherLevelException(Throwable cause) {

super(cause);

}

}

Note

Most standard exceptions have chaining-aware constructors. For exceptions that don't, you can set the cause using Throwable's initCause method. Not only does exception chaining let you access the cause programmatically (with getCause ), but it integrates the cause's stack trace into that of the higher-level exception.

Principle

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

Solutions:

  1. The best way to deal with exceptions from lower layers is to avoid them by checking the validity of the higher-level method's parameters before passing them on to lower layers.
  2. The next best thing is to have the higher layer silently work around these exceptions, insulating the caller of the higher-level method from lower-level problems.(Log the exception using some appropriate logging facility such as java.util.logging which allows an administrator to investigate the problem, while insulating the client code and the end user from it.

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 63).