捕获嵌套到另一个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。
例外情况往往嵌套有三个原因:
-
您已确定原始exception的详细信息不太可能对应用程序的错误恢复有用…但您希望保留它们以用于诊断目的。
-
您正在实现不允许检查exception的API方法,但您的代码(不可避免地)会抛出此类exception。 (一种常见的解决方法是在未经检查的exception中“走私”exception。)
-
您正在懒惰并将一组不相关的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 extends Throwable> 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的目的是什么。