用Guava辅助Throwable异常处理

  Guava的 Throwables 工具经常可让exception处理更方便。

  Propagation

  有时候,你会想把捕获的exception抛到上一个try/catch块。对于 RuntimeException 和 Error 尤其如此,它们不须要 try/catch 块,但可能被其余的 try/catch 块无心捕获。

  Guava 提供了一些工具来简化propagate exception。例如:

  try{

  someMethodThatCouldThrowAnything();

  }catch(IKnowWhatToDoWithThisException e){

  handle(e);

  }catch(Throwable t){

  Throwables.propagateIfInstanceOf(t, IOException.class);

  Throwables.propagateIfInstanceOf(t, SQLException.class);

  throw Throwables.propagate(t);

  }

  这里的每一个方法都会抛出它们本身的exception,可是throw最终结果 —— 如,throw Throwables.propagate(t) —— 对编译检查有指示做用,提示这里确定会抛出一个exception。

  这里是Guava提供的propagation方法的简单总结:

  参数形式解释

  RuntimeException propagate(Throwable)若是参数throwable是 RuntimeException 或 Error 则原样propagate,不然将它包入 RuntimeException 中抛出。保证抛出。返回值是 RuntimeException 类型,所以你能够像上面那样写 throw Throwables.propagate(t) ,这样Java编译器会明白这一行确定会抛出一个exception。

  void propagateIfInstanceOf(Throwable, Class) throws X仅当参数throwable是 X 类型时,原样propagate。

  void propagateIfPossible(Throwable)仅当参数throwable是 RuntimeException 或 Error 类型时,原样propagate。

  void propagateIfPossible(Throwable, Class) throws X仅当参数 throwable 是 RuntimeException 或 Error 或 X 类型时,原样propagate。

  Throwables.propagate的用途 模仿Java 7的多重catch和从新throw

  通常来讲,调用者若是想要让exception沿着调用栈传播,他只要不写 catch 块就能够了。既然他不打算在exception后恢复,他恐怕也不须要写入log或者采起什么其余行动。他可能须要进行一些清理工做,可是不管有没有expction都会须要,所以清理工做会放在 finally 块中。尽管如此,会从新throw的 catch 块有时仍是有意义的:也许调用者想要在传播exception以前先更新崩溃计数器,或者他只想在特定条件下传播exception。

  只有一种exception的时候,catch和从新throw是简单直接的。麻烦的是有多种exception的时候:

  @Overridepublicvoid run(){

  try{

  delegate.run();

  }catch(RuntimeException e){

  failures.increment();

  throw e;

  }catch(Error e){

  failures.increment();

  throw e;

  }

  }

  Java 7用 multicatch 来解决这个问题:

  }catch(RuntimeException|Error e){

  failures.increment();

  throw e;

  }

  但不用Java 7的用户就没办法了。他们也想写以下的代码,但编译器不容许抛出Throwable类型的变量:

  }catch(Throwable t){

  failures.increment();

  throw t;

  }

  解决方案是用 throw Throwables.propagate(t) 来替换 throw t 。仅就这种状况而言, Throwables.propagate 跟以前代码的功能彻底相同。可是,代码里写 Throwables.propagate 很容易有一种隐藏的反作用。具体来讲,要注意上面这种模式只适用于 RuntimeException 和 Error。若是 catch 块可能捕捉checked exception,你还须要调用 propagateIfInstanceOf 来保证正常功能,由于 Throwables.propagate 没法直接传播checked exception。

  整体来讲,这种 propagate 的用法效果通常。在Java 7下不必这样作。在其余版本的Java下,这样能略微减小重复,可是一个简单的Extract Method重构也能够达到一样效果。另外,使用 propagate makes it easy to accidentally wrap checked exceptions.

  无用功:把 throws Throwable 转化为 throws Exception

  某些API,尤为是Java reflection API 和 (相应的) JUnit,有抛出 Throwable 的方法。运用这些API可能很麻烦,由于就算是最通用的API通常也只声明throws Exception。 Throwables.propagate 是为非 Exception ,非 Error 的 Throwable 准备的。这个例子声明了一个执行JUnit测试的 Callable :

  public void call() throws Exception{

  try{

  FooTest.super.runTest();

  }catch(Throwable t){

  Throwables.propagateIfPossible(t,Exception.class);

  Throwables.propagate(t);

  }

  return null;

  }

  这里不必propagate(),而且第二行与="throw new RuntimeException(t)"等价。 (顺便说一句:这个例子也提醒了我 propagateIfPossible 可能使人迷惑,由于它不只传播参数指定的类型,也传播 Error 和 RuntimeException。)

  这种模式 (或者相似的写法,如"throw new RuntimeException(t)") 在Google的代码库里至少出现 30 次。(搜索'propagateIfPossible[^;]* Exception.class[)];'试试。) 采用"throw new RuntimeException(t)"写法的略占多数。咱们也有可能想要一个"throwWrappingWeirdThrowable"方法来作Throwable到Exception的转换,可是既然两行就能搞定,这个方法仍是没有太大必要,除非咱们要废除propagateIfPossible方法 www.yztrans.com

  Throwables.propagate有争议的用法 有争议:把 checked exception 转化为 unchecked exception

  理论上,unchecked exception表示有bug,checked exceptions表示在你控制范围以外的问题。但在实践上,即便JDK有时也会用错 (至少,对于某些方法,没有广泛认同的正确答案)。

  所以,有时调用者须要让这两种exception类型相互转化:

  try{

  return Integer.parseInt(userInput);

  }catch(NumberFormatException e){

  throw new InvalidInputException(e);

  }

  try{

  return publicInterfaceMethod.invoke();

  }catch(IllegalAccessException e){

  throw new AssertionError(e);

  }

  有时候,这些调用者会用 Throwables.propagate 。有什么坏处呢?最主要的问题是代码的含义不太明显。throw Throwables.propagate(ioException) 有什么效果?throw new RuntimeException(ioException) 有什么效果?这两行代码功能是相同的,但后者更直白。前者令人生疑:"这是在作什么?应该不仅是打包成 RuntimeException 吧?若是只为这个,为什么不写一个wrapper方法呢?"只能认可,部分问题在于"propagate"这个名字很含糊。(它是一个抛出未声明exception的方式吗?) 也许换成"wrapIfChecked"会好一些。但即便叫这个名字,在已知checked exception上调用它也没有什么优点。可能还会有反作用: 也许会有比普通 RuntimeException 更合适的抛出类型 -- 好比, IllegalArgumentException。

  咱们有时也会看到在exception仅仅有多是checked exception时用 propagate 。相对来讲,这种作法后果小一些,也不那么直白:

  }catch(RuntimeException e){

  throw e;

  }catch(Exception e){

  throw new RuntimeException(e);

  }

  }catch(Exception e){

  throw Throwables.propagate(e);

  }

  尽管如此,这里不可忽视的问题在于将checked exception转化为unchecked exception的行为自己。在某些状况下是无可厚非的,但更多的时候这样作是在逃避对常规 checked exception 的处理。这让咱们思考checked exception自己是否就是一个坏主意。我不想说得这么深刻。姑且说 ,Throwables.propagate 不是让 Java 使用者用来忽略 IOException 及相似异常的。

  有争议: Exception隧道

  可是当你实现一个不容许throw exception的方法时怎么办呢?有时你须要把exception打包在unchecked exception中。这样没问题,但一样的,对于单纯的打包 propagate 没有必要。事实上,本身实现打包会更好一些:若是你把每一个exception(而不仅是checked exception)打包,那就能够在另外一端解包,减小特殊处理。另外,最好打包成自定义的exception类型。

  有争议: 从新抛出其余线程的exception

  try{

  return future.get();

  }catch(ExecutionException e){

  throw Throwables.propagate(e.getCause());

  }

  这里有几件要考虑的事:

  对于checked exception:参见上面的"把 checked exception 转化为 unchecked exception"一节。但若是此处已知不会抛出checked exception呢? (也许是 Runnable 的结果。) 如上所述,你能够catch这个exception而后抛出 AssertionError ;propagate 没有什么用。特别的是,对于Future,也能够考虑Futures.get。

  对于非Exception,非Error的Throwable。(好吧,这个可能性不大,可是若是你试图直接从新throw它,编译器会强迫你考虑这种可能) 参考上面的 "把 throws Throwable 转化为 throws Exception" 一节.

  对于unchecked exception或error。那么它会直接被从新throw。不幸的是,它的stack trace会显示原先产生exception的线程,而不是当前传播到的线程。通常最好的结果是把两个线程的stack trace都包括在exception chain中,就像 get 抛出的 ExecutionException 同样。(这其实不是 propagate 的问题; 这是全部把 exception 在另外一个线程抛出的共同问题。)

  因果链

  Guava让研究一个exception的因果链(causal chain)更简单了一些,它提供了如下3个颇有用的方法,功能顾名思义:

  Throwable getRootCause(Throwable)

  List getCausalChain(Throwable)

  String getStackTraceAsString(Throwable) www.lefeng123.com  托福答案

 app

相关文章
相关标签/搜索