任何人都不敢说自己的代码没有bug,所以程序抛异常是再经常不过的事情,有时候,你会想把捕获的exception抛到上一个try/catch块。对于 RuntimeException 和 Error 尤为如此,它们不需要try/catch 块,但可能被其他的 try/catch 块无意捕获。
你没想捕获它们,但是声明捕获Throwable和Exception的时候,也包括了了Error或RuntimeException
Guava提供了若干方法,来判断异常类型并且重新传播异常。例如:
try {
someMethodThatCouldThrowAnything();
} catch (IKnowWhatToDoWithThisException e) {
handle(e);
} catch (Throwable t) {
Throwables.propagateIfInstanceOf(t, IOException.class);
Throwables.propagateIfInstanceOf(t, SQLException.class);
throw Throwables.propagate(t);
}
所有这些方法都会自己决定是否要抛出异常,但也能直接抛出方法返回的结果例如:throw Throwables.propagate(t); 这样可以向编译器声明这里一定会抛出异常
Guava中的异常传播方法简要列举如下:
方法 | 说明 |
---|---|
RuntimeException propagate(Throwable) | 如果Throwable是Error或RuntimeException,直接抛出;否则把Throwable包装成RuntimeException抛出。返回类型是RuntimeException,所以你可以像上面说的那样写成throw Throwables.propagate(t),Java编译器会意识到这行代码保证抛出异常。 |
void propagateIfInstanceOf( Throwable, Class) throws X | Throwable类型为X才抛出 |
void propagateIfPossible( Throwable) | Throwable类型为Error或RuntimeException才抛出 |
void propagateIfPossible( Throwable, Class) throws X | Throwable类型为X, Error或RuntimeException才抛出 |
下面主要说明一下Throwables.propagate的用法
通常来说,如果调用者想让异常传播到栈顶,他不需要写任何catch代码块。因为他不打算从异常中恢复,他可能就不应该记录异常,或者有其他的动作。他可能是想做一些清理工作,但通常来说,无论操作是否成功,清理工作都要进行,所以清理工作可能会放在finallly代码块中。但有时候,捕获异常然后再抛出也是有用的:也许调用者想要在异常传播之前统计失败的次数,或者有条件地传播异常。
当只对一种异常进行捕获和再抛出时,代码可能还是简单明了的。但当多种异常需要处理时,却可能变得一团糟:
@Override
public void run() {
try {
delegate.run();
} catch (RuntimeException e) {
failures.increment();
throw e;
}catch (Error e) {
failures.increment();
throw e;
}
}