@XingdingCAO
2017-12-23T09:48:21.000000Z
字数 2259
阅读 1695
exception
Java
看到一个你执行的任务毫无关联的异常是十分恼人的。这种情况通常是:你的程序抛出的异常是从低层次传播而来的。这样的异常不仅是无关的,而且用实现细节污染了高层次的API。假如后续的改进更改了实现细节,那么高层次得到的异常也会随之改变。因此,虽然高层次API没有变动,但因为实现细节体现在了高层次的API中,之前依赖于旧版本中的异常的客户程序就会在新版本失效。
为了避免上述问题,高层次应该捕获低层次抛出的异常,然后抛出可以根据高层抽象解释的异常。这就是我们常说的异常转译。
// Exception Translation
try {
// Use lower-level abstraction to do our bidding
...
} catch(LowerLevelException e) {
throw new HigherLevelException(...);
}
java.util.AbstractSequentialList<E>
就是一个很好的例子。它是List<E>
的一个骨架实现。
/**
* This class provides a skeletal implementation of the <tt>List</tt>
* interface to minimize the effort required to implement this interface
* backed by a "sequential access" data store (such as a linked list). For
* random access data (such as an array), <tt>AbstractList</tt> should be used
* in preference to this class.<p>
*/
public abstract class AbstractSequentialList<E> extends AbstractList<E> {
/**
* Returns the element at the specified position in this list.
*
* <p>This implementation first gets a list iterator pointing to the
* indexed element (with <tt>listIterator(index)</tt>). Then, it gets
* the element using <tt>ListIterator.next</tt> and returns it.
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
try {
return listIterator(index).next();
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
一种异常转译的特殊形式叫做异常链。适用于低层次的异常可能对于调试由于高层次异常产生的问题有用,低层次异常传递给高层次异常来供其访问。
// Exception Translation
try {
// Use lower-level abstraction to do our bidding
...
} catch(LowerLevelException cause) {
throw new HigherLevelException(cause);
}
高层次的异常构造方法将传入的cause
参数传递给chaining-aware
(异常链感知)的父类构造方法,最终传递至一个chaining-aware
(异常链感知)的构造方法。cause
参数的类型通常是Throwable
。
// Exception with chaining-aware constructor
class HigherLevelException extends Exception {
HigherLevelException(Throwable cause) {
super(cause);
}
}
大多数标准异常都提供了chaining-aware
(异常链感知)的构造方法。如果没有提供,那么你可以使用Throwable
接口中的initCause
方法。不仅异常链让你可以在程序上访问异常产生的原因(getCause
方法),而且它将异常原因的堆栈跟踪集成在了高层次异常中。
异常转译对于无脑(mindless)地直接抛出低层次异常已经大有改善,但是也不应该过度地滥用。最好的处理方式其实是避免在低层次抛出异常,为了实现这一目标,高层次在将参数传递给低层次之前,应当验证获取的参数的正确性。
如果不能保证低层次不抛出异常,低一等的处理方式就是让高层次静默处理这些异常,将高层次的调用者与低层次的异常隔离开来。这一情况下,将异常记录在日志(例如:使用java.util.logging
)可能是恰当的,这样做可以使得管理人员调查问题,而客户程序和端用户则无从知晓。
总之,如果没有办法在低层次阻止或处理异常,那么使用在高层次使用异常转译是恰当的。除非能够保证所有低层次异常都对于高层次是有用的,那么可以直接抛出。
异常链则为两端提供了最好的解决方式:既允许抛出恰当的高层次异常,又捕获了低层次的原因来用于错误分析。