Effective Java 第三版——73.抛出合乎于抽象的异常

Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,因此JDK 最好下载 JDK 9以上的版本。java

Effective Java, Third Edition

#73. 抛出合乎于抽象的异常git

当一个方法抛出一个与它所执行的任务没有明显关联的异常时,这是使人不安的。在方法传播由低层(lower-level)抽象抛出的异常时,会常常发生这种状况。它不只使人不安,并且用实现细节“污染”了上层的API。若是上层(higher layer)的实如今之后的版本中发生变化,那么它抛出的异常也会发生变化,可能会破坏现有的客户端程序。程序员

为了不这个问题,上层(higher layers)应该捕获低层( lower-level )的异常,并在它们的位置抛出能够用上层级别(higher-level )抽象来解释的异常。这个习语被称为异常转译:github

// Exception Translation
try {
    ... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException e) {
    throw new HigherLevelException(...);
}

如下的异常转转译的示例是来自AbstractSequentialList类,该类是List接口的骨架实现(skeletal implementation )(条目 20)。 在此示例中,异常转译由List <E>接口中的get方法规范强制要求的:编程

/**
 * 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);
    }
}

若是较低级别的异常可能有助于调试致使较高级别异常的问题,则须要一种称为异常链(exception chaining )的特殊异常转译形式。低层异常(缘由)传递给高层异常,高层异常提供一个访问器方法(Throwable的getCause方法)来检索低层异常:工具

// Exception Chaining
try {
    ... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException cause) {
    throw new HigherLevelException(cause);
}

高级异常的构造方法将缘由传递给一个感知链(chaining-aware)的父类构造方法,所以它最终被传递给Throwable的一个感知链的构造方法,好比Throwable(Throwable):this

// Exception with chaining-aware constructor
class HigherLevelException extends Exception {
    HigherLevelException(Throwable cause) {
        super(cause);
    }
}

大多数标准异常都有感知链的构造方法。对于没有这样作的异常,可使用Throwable的initCause方法设置缘由。异常连接不只容许你以编程方式访问缘由(使用getCause),并且还将缘由的堆栈跟踪集成到更高级别异常的堆栈跟踪中。调试

虽然异常转译优于低层异常的无心识传播,但不该过分使用。 在可能的状况下,处理较低层异常的最佳方法是经过确保较低级别的方法成功执行来避免异常。 有时能够经过检查更高级别方法的参数的有效性,而后再将它们传递到较低层来完成此操做。日志

若是不可能防止来自较低层的异常,那么接下来最好的事情就是让较高层静默地解决这些异常,从而使较高级别方法的调用者与较低级别的问题隔离开来。 在这些状况下,使用某些适当的日志记录工具(如java.util.logging)记录异常多是适当的。 这容许程序员调查问题,同时把使用者和客户端代码隔离开。code

总之,若是没法阻止或处理较低层的异常,那么使用异常转译,除非较低级别的方法刚好保证其全部异常都适用于较高级别。 异常连接提供了一箭双鵰的优点:它容许抛出适当的更高级别异常,同时能够捕获失败分析的根本缘由(条目 75)。

相关文章
相关标签/搜索