@XingdingCAO
2017-12-23T01:48:21.000000Z
字数 2259
阅读 2062
exception Java
看到一个你执行的任务毫无关联的异常是十分恼人的。这种情况通常是:你的程序抛出的异常是从低层次传播而来的。这样的异常不仅是无关的,而且用实现细节污染了高层次的API。假如后续的改进更改了实现细节,那么高层次得到的异常也会随之改变。因此,虽然高层次API没有变动,但因为实现细节体现在了高层次的API中,之前依赖于旧版本中的异常的客户程序就会在新版本失效。
为了避免上述问题,高层次应该捕获低层次抛出的异常,然后抛出可以根据高层抽象解释的异常。这就是我们常说的异常转译。
// Exception Translationtry {// 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 Translationtry {// 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 constructorclass HigherLevelException extends Exception {HigherLevelException(Throwable cause) {super(cause);}}
大多数标准异常都提供了chaining-aware(异常链感知)的构造方法。如果没有提供,那么你可以使用Throwable接口中的initCause方法。不仅异常链让你可以在程序上访问异常产生的原因(getCause方法),而且它将异常原因的堆栈跟踪集成在了高层次异常中。
异常转译对于无脑(mindless)地直接抛出低层次异常已经大有改善,但是也不应该过度地滥用。最好的处理方式其实是避免在低层次抛出异常,为了实现这一目标,高层次在将参数传递给低层次之前,应当验证获取的参数的正确性。
如果不能保证低层次不抛出异常,低一等的处理方式就是让高层次静默处理这些异常,将高层次的调用者与低层次的异常隔离开来。这一情况下,将异常记录在日志(例如:使用java.util.logging)可能是恰当的,这样做可以使得管理人员调查问题,而客户程序和端用户则无从知晓。
总之,如果没有办法在低层次阻止或处理异常,那么使用在高层次使用异常转译是恰当的。除非能够保证所有低层次异常都对于高层次是有用的,那么可以直接抛出。
异常链则为两端提供了最好的解决方式:既允许抛出恰当的高层次异常,又捕获了低层次的原因来用于错误分析。