【问题标题】:How do I use Throwables.propagateIfInstanceOf() from Google Guava?如何使用 Google Guava 的 Throwables.propagateIfInstanceOf()?
【发布时间】:2011-02-23 11:44:13
【问题描述】:

The javadoc example

  try {
    someMethodThatCouldThrowAnything();
  } catch (IKnowWhatToDoWithThisException e) {
    handle(e);
  } catch (Throwable t) {
    Throwables.propagateIfInstanceOf(t, IOException.class);
    Throwables.propagateIfInstanceOf(t, SQLException.class);
    throw Throwables.propagate(t);
  }

不是很具体。一个真正的程序会是什么样子?我不太明白Throwables.propagateIfInstanceOf(Throwable, Class)propagate()propagateIfPossible() 方法的目的。我什么时候使用它们?

【问题讨论】:

    标签: java guava


    【解决方案1】:

    这些方法的目的是提供一种方便的方法来处理检查的异常。

    Throwables.propagate() 是一种将已检查异常封装到未检查异常中的常用习惯用法的简写(以避免在方法的 throws 子句中声明它)。

    Throwables.propagateIfInstanceOf() 用于追溯检查的异常,就像它们的类型在方法的throws 子句中声明一样。

    换句话说,有问题的代码

    public void doSomething() 
        throws IOException, SQLException {
    
        try {
            someMethodThatCouldThrowAnything();
        } catch (IKnowWhatToDoWithThisException e) {
            handle(e);
        } catch (Throwable t) {
            Throwables.propagateIfInstanceOf(t, IOException.class);
            Throwables.propagateIfInstanceOf(t, SQLException.class);
            throw Throwables.propagate(t);
        }  
    }
    

    是以下代码的简写:

    public void doSomething() 
        throws IOException, SQLException {
    
        try {
            someMethodThatCouldThrowAnything();
        } catch (IKnowWhatToDoWithThisException e) {
            handle(e);
        } catch (SQLException ex) {
            throw ex;
        } catch (IOException ex) {
            throw ex;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }  
    }
    

    另请参阅:

    【讨论】:

    • 您编写的方法的第二个版本不等效...您需要再添加两个 catch 块来重新抛出异常...一个用于 RuntimeException 和一个为ErrorThrowables.propagate 仅将 throwable 包装在 RuntimeException 中,前提是它还不是未经检查的异常。
    • 我还是不明白。如果我想传播异常,为什么还要捕获异常?我能做到: public void doSomething() throws IOException, SQLException { try { someMethodThatCouldThrowAnything(); } 捕捉(IKnowWhatToDoWithThisException e){句柄(e); } }。这不是一个真实的例子......
    • @Jeny:你不能这样做是因为`someMethodThatCouldThrowAnything()` 可以抛出除IOExceptionSQLException 之外的一些检查异常。
    • True,然后我们将其包装在 RuntimeException 中,而不是按原样重新处理。这是一个不同的用例,完全取决于 Throwables.propagate(t) 但它不能解释没有这种行为的场景。还是我们总是用propagate() 结束块?整个想法是否只是将我们可以按原样重新扔掉的所有东西,其余的都放在 RE 中,没有别的?然后我开始明白了……
    【解决方案2】:

    我浏览了 Guava Throwables 的文档,但我没有发现它们真的很有用。使用 throw new RuntimeException(e) 比 Throwables.propagate() 更容易理解,在你想抛出一个封装了一个已检查异常的未检查异常的场景中。

    【讨论】:

    • 您不必检查您的可抛出异常是特定的已检查异常、运行时异常还是错误。它可以防止过多的可抛出封装。看到数公里的包装 RuntimeException 导致很长的堆栈跟踪要经过并不罕见。最后看到唯一的最后一个有价值。
    【解决方案3】:

    我可以为任何会发现这很有用的人提供一个场景,如果您有一个包装任何抛出异常的方法,那么这可用于将原因解包/转换为特定异常。

    示例:Guava 的 LoadingCache 中的 get 方法将所有已检查的异常包装到 ExecutionException 中。文档指出可以使用getCause() 检查异常。

    这里Throwables.propagateIfInstanceOf可以用来抛出特定的异常给调用方法来处理,如果我们知道cache.get()会抛出这些异常(可能是LoadingCache特有的,但是如果value是misisng,缓存会尝试加载一个可以抛出已检查异常的值)。

    public String getCacheValue(String key) throws SQLException{
      try{
           return cache.get(key);
      }catch(ExecutedException ex){
           Throwables.propagateIfInstanceOf(ex.getCause(), SQLException.class);
           Throwables.propagate(ex);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-03-15
      • 1970-01-01
      • 1970-01-01
      • 2011-08-20
      • 1970-01-01
      • 2011-10-25
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      相关资源
      最近更新 更多