我想捕获一个异常,它嵌套到另一个异常中。 我现在这样做:
} 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'");
}
}
有没有办法更高效,更优雅?
答案 0 :(得分:25)
没有更优雅的方式来选择性地“捕获”嵌套异常。我想如果你做了这种嵌套异常捕获很多,你可以将代码重构为一个通用的实用方法。但它仍然不会优雅或高效。
优雅的解决方案是取消异常嵌套。要么不首先链接异常,要么(有选择地)解包并重新抛出堆栈中的嵌套异常。
异常倾向于嵌套有三个原因:
您已确定原始异常的详细信息不太可能对应用程序的错误恢复有用...但您希望保留它们以用于诊断目的。
您正在实现不允许特定已检查异常的API方法,但您的代码不可避免地会抛出该异常。常见的解决方法是在未经检查的异常中“检查”已检查的异常。
您正懒惰并将多种不相关的异常集合转换为单个异常,以避免在方法签名 1 中出现大量已检查的异常。< / p>
在第一种情况下,如果您现在需要区分包装的异常,那么您的初始假设是不正确的。最好的解决方案是更改方法签名,以便您可以摆脱嵌套。
在第二种情况下,您可能应该在控件通过有问题的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()