Java 捕获嵌套在另一个异常中的异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2955458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Catching an exception that is nested into another exception
提问by
I want to catch an exception, that is nested into another exception. I'm doing it currently this way:
我想捕获一个异常,它嵌套在另一个异常中。我目前正在这样做:
} 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'");
}
}
Is there a way to do this more efficient and elegant?
有没有办法更有效和优雅地做到这一点?
采纳答案by Stephen C
There is no more elegant way of selectively "catching" nested exceptions. I suppose if you did this kind of nested exception catching a lot, you could possibly refactor the code into a common utility method. But it still won't be either elegant or efficient.
没有更优雅的方式来选择性地“捕获”嵌套异常。我想如果你经常捕获这种嵌套的异常,你可能会将代码重构为一个通用的实用方法。但它仍然不会优雅或高效。
The elegant solution is to do away with the exception nesting. Either don't chain the exceptions in the first place, or (selectively) unwrap and rethrow the nested exceptions further up the stack.
优雅的解决方案是取消异常嵌套。要么一开始就不要链接异常,要么(有选择地)解包并重新抛出嵌套的异常进一步向上堆栈。
Exceptions tend to be nested for 3 reasons:
出于 3 个原因,异常倾向于嵌套:
You have decided that the details of the original exception are unlikely to be useful for the application's error recovery ... but you want to preserve them for diagnostic purposes.
You are implementing API methods that don't allow a specific checked exception but your code unavoidablythrows that exception. A common workaround is to "smuggle" the checked exception inside an unchecked exception.
You are being lazy and turning a diverseset of unrelated exceptions into a single exception to avoid having lots of checked exceptions in your method signature1.
您已确定原始异常的详细信息不太可能对应用程序的错误恢复有用……但您希望保留它们以用于诊断目的。
您正在实现不允许特定检查异常的 API 方法,但您的代码不可避免地抛出该异常。一种常见的解决方法是在未检查异常中“走私”已检查异常。
您很懒惰,将各种不相关的异常转换为单个异常,以避免在您的方法签名1 中有大量已检查的异常。
In the first case, if you now need to discriminate on the wrapped exceptions, then your initial assumptions were incorrect. The best solution is change method signatures so that you can get rid of the nesting.
在第一种情况下,如果您现在需要区分包装的异常,那么您最初的假设是不正确的。最好的解决方案是更改方法签名,以便您可以摆脱嵌套。
In the second case, you probably should unwrap the exceptions as soon as control has passed the problematic API method.
在第二种情况下,您可能应该在控制通过有问题的 API 方法后立即解包异常。
In the third case, you should rethink your exception handling strategy; i.e. do it properly2.
在第三种情况下,您应该重新考虑您的异常处理策略;即做正确2。
1 - Indeed, one of the semi-legitimate reasons for doing this has gone away due to the introduction of the multi-exception catch syntax in Java 7.
1 - 事实上,由于在 Java 7 中引入了多异常捕获语法,这样做的半合法原因之一已经消失。
2 - Don't change your API methods to throws Exception
. That only makes things worse. You now have to either "handle" or propagate Exception
each time you call the methods. It is a cancer ...
2 - 不要将您的 API 方法更改为throws Exception
. 那只会让事情变得更糟。您现在必须在Exception
每次调用方法时“处理”或传播。这是一种癌症...
回答by Petar Minchev
I doubt, but you can check with instanceof
if the exception is of the correct type.
我怀疑,但您可以检查instanceof
异常是否属于正确类型。
Edit: There should be a reason that the nested exception is wrapped, so you have to ask yourself what is the purpose of catching the nested one.
编辑:嵌套异常被包装应该是有原因的,所以你必须问自己捕捉嵌套异常的目的是什么。
回答by Marc
You should add some checks to see if e.getCause().getCause()
is really a MyException
. Otherwise this code will throw a ClassCastException
. I would probably write this like:
您应该添加一些检查以查看是否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("...");
}
}
回答by Peter Tillemans
I see no reason why you want exception handling to be efficient and elegant, I settle for effective. They're called Exceptions for a reason.
我看不出为什么您希望异常处理高效和优雅,我满足于有效。它们被称为异常是有原因的。
This code will be a maintenance nightmare. Can't you redesign the call stack to throw the Exception you are interested in? If it is important the method signatures should show it and not hide it wrapped in 2 other exceptions.
此代码将是维护噩梦。你不能重新设计调用堆栈来抛出你感兴趣的异常吗?如果它很重要,方法签名应该显示它,而不是将它隐藏在其他 2 个异常中。
The first (e != null) is unnecessary.
第一个 (e != null) 是不必要的。
And you can change the 3rd better to e.getCause().getCause() instanceof MyException)
您可以将第三个更好地更改为 e.getCause().getCause() instanceof MyException)
回答by Stephen C
The ExceptionUtils#getRootCause()method can come in very handy in such situations.
在这种情况下,ExceptionUtils#getRootCause()方法可以派上用场。
回答by Shrikant Lohiya
You can do as below:
您可以执行以下操作:
catch (RemoteAccessException e) {
int index = ExceptionUtils.indexOfThrowable(e, MyExcetption.class)
if (index != -1) {
//handleMyException
} else {
}
}
回答by Ricardo van den Broek
I just solved a problem like this by writing a simple utility method, which will check the entire caused-by chain.
我刚刚通过编写一个简单的实用程序方法解决了这样的问题,该方法将检查整个起因链。
/**
* 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);
}
When you use it, you would just create a list of if's from most specific Exception to least specific, with a fallback else-clause:
当您使用它时,您只需创建一个从最具体的异常到最不具体的 if 列表,并带有一个备用 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'");
}
}