捕获嵌套到另一个exception中的exception

我想捕获一个exception,它嵌套到另一个exception中。 我这样做是这样的:

} 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'"); } } 

有没有办法更有效和优雅地做到这一点?

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

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

例外情况往往嵌套有三个原因:

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

  2. 您正在实现不允许检查exception的API方法,但您的代码(不可避免地)会抛出此类exception。 (一种常见的解决方法是在未经检查的exception中“走私”exception。)

  3. 您正在懒惰并将一组不相关的exception转换为单个exception,以避免在方法签名1中出现大量已检查的exception。

在第一种情况下,如果您需要区分包装的exception,您的初始假设/设计是不正确的,理想的解决方案是更改方法签名,以便您可以摆脱嵌套。

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

在第三种情况下,您应该重新考虑您的exception处理策略; 即做得好。


1 – 事实上,由于在Java 7中引入了多exception捕获语法,因此实现此目的的一个半正当理由已经消失。

在这种情况下, ExceptionUtils #getRootCause()方法可以派上用场。

您应该添加一些检查以查看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("..."); } } 

我认为没有理由要求exception处理高效而优雅,我认为有效。 他们被称为例外是有原因的。

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

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

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

你可以这样做:

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

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

  /** * 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 isOfOrCausedBy) { if (caught == null) return false; else if (isOfOrCausedBy.isAssignableFrom(caught.getClass())) return true; else return isCausedBy(caught.getCause(), isOfOrCausedBy); } 

当您使用它时,您只需使用fallback else子句创建一个从最具体的exception到最不具体的if的列表:

 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'"); } } 

我怀疑,但是如果exception类型正确,你可以查看instanceof

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