捕获嵌套到另一个异常中的异常

时间:2010-06-02 06:26:44

标签: java exception try-catch nested-exceptions

我想捕获一个异常,它嵌套到另一个异常中。 我现在这样做:

} catch (RemoteAccessException e) {
    if (e != null && e.getCause() != null && e.getCause().getCause() != null) {
        MyException etrp = (MyException) e.getCause().getCause();
        ...
    } else {
        throw new IllegalStateException("Error at calling service 'service'");
    }
}

有没有办法更高效,更优雅?

8 个答案:

答案 0 :(得分:25)

没有更优雅的方式来选择性地“捕获”嵌套异常。我想如果你做了这种嵌套异常捕获很多,你可以将代码重构为一个通用的实用方法。但它仍然不会优雅或高效。

优雅的解决方案是取消异常嵌套。要么不首先链接异常,要么(有选择地)解包并重新抛出堆栈中的嵌套异常。

异常倾向于嵌套有三个原因:

  1. 您已确定原始异常的详细信息不太可能对应用程序的错误恢复有用...但您希望保留它们以用于诊断目的。

  2. 您正在实现不允许特定已检查异常的API方法,但您的代码不可避免地会抛出该异常。常见的解决方法是在未经检查的异常中“检查”已检查的异常。

  3. 您正懒惰并将多种不相关的异常集合转换为单个异常,以避免在方法签名 1 中出现大量已检查的异常。< / p>

  4. 在第一种情况下,如果您现在需要区分包装的异常,那么您的初始假设是不正确的。最好的解决方案是更改方法签名,以便您可以摆脱嵌套。

    在第二种情况下,您可能应该在控件通过有问题的API方法后立即解包异常。

    在第三种情况下,您应该重新考虑您的异常处理策略;即正确地做到 2


    1 - 事实上,由于在Java 7中引入了多异常捕获语法,其中一个半合法的理由已经消失。

    2 - 请勿将API方法更改为throws Exception。这只会让事情变得更糟。现在,每次调用方法时,您都必须“处理”或传播Exception。这是一种癌症......

答案 1 :(得分:19)

在这种情况下,ExceptionUtils#getRootCause()方法非常方便。

答案 2 :(得分:18)

您应该添加一些检查,以查看e.getCause().getCause()是否真的是MyException。否则此代码将抛出ClassCastException。我可能会这样写:

} catch(RemoteAccessException e) {
    if(e.getCause() != null && e.getCause().getCause() instanceof MyException) {
        MyException ex = (MyException)e.getCause().getCause();
        // Do further useful stuff
    } else {
        throw new IllegalStateException("...");
    }
}

答案 3 :(得分:3)

我只是通过编写一个简单的实用程序方法解决了这样的问题,该方法将检查整个因果链。

  /**
   * Recursive method to determine whether an Exception passed is, or has a cause, that is a
   * subclass or implementation of the Throwable provided.
   *
   * @param caught          The Throwable to check
   * @param isOfOrCausedBy  The Throwable Class to look for
   * @return  true if 'caught' is of type 'isOfOrCausedBy' or has a cause that this applies to.
   */
  private boolean isCausedBy(Throwable caught, Class<? extends Throwable> isOfOrCausedBy) {
    if (caught == null) return false;
    else if (isOfOrCausedBy.isAssignableFrom(caught.getClass())) return true;
    else return isCausedBy(caught.getCause(), isOfOrCausedBy);
  }

使用它时,您只需创建一个if列表,从最具体的Exception到最不具体的Exception,并附带一个else-子句:

try {
  // Code to be executed
} catch (Exception e) {
  if (isCausedBy(e, MyException.class)) {
    // Handle MyException.class
  } else if (isCausedBy(e, AnotherException.class)) {
    // Handle AnotherException.class
  } else {
    throw new IllegalStateException("Error at calling service 'service'");
  }
}

答案 4 :(得分:2)

我认为没有理由要求异常处理高效优雅,我认为有效。出于某种原因,他们被称为例外。

此代码将成为维护的噩梦。难道你不能重新设计调用堆栈来抛出你感兴趣的Exception吗?如果重要的话,方法签名应该显示它,而不是隐藏它包含在其他2个例外中。

第一个(e!= null)是不必要的。

你可以将第3个更好地更改为e.getCause()。getCause()instanceof MyException)

答案 5 :(得分:1)

您可以执行以下操作:

catch (RemoteAccessException e) {
    int index = ExceptionUtils.indexOfThrowable(e, MyExcetption.class)
    if (index != -1) {
         //handleMyException
    } else {
    }
}

答案 6 :(得分:0)

我怀疑,但如果异常类型正确,您可以查看instanceof

编辑:应该有一个嵌套异常被包装的原因,所以你必须问自己捕获嵌套异常的目的是什么。

答案 7 :(得分:0)

我想您也可以像here一样使用ExceptionUtils.throwableOfThrowable()