Java 检查某个异常类型是否是嵌套异常中的原因(原因等......)的最佳方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/610628/
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
Best way to check whether a certain exception type was the cause (of a cause, etc ...) in a nested exception?
提问by Yang Meyer
I am writing some JUnit tests that verify that an exception of type MyCustomException
is thrown. However, this exception is wrapped in other exceptions a number of times, e.g. in an InvocationTargetException, which in turn is wrapped in a RuntimeException.
我正在编写一些 JUnit 测试来验证是否抛出了类型MyCustomException
异常。但是,此异常多次包装在其他异常中,例如在 InvocationTargetException 中,而后者又包装在 RuntimeException 中。
What's the best way to determine whether MyCustomException somehow caused the exception that I actually catch? I would like to do something like this (see underlined):
确定 MyCustomException 是否以某种方式导致我实际捕获的异常的最佳方法是什么?我想做这样的事情(见下划线):
try { doSomethingPotentiallyExceptional(); fail("Expected an exception."); } catch (RuntimeException e) { if (!e.
wasCausedBy(MyCustomException.class) fail("Expected a different kind of exception."); }
I would like to avoid calling getCause()
a few "layers" deep, and similar ugly work-arounds. Is there a nicer way?
我想避免调用getCause()
一些“层”深,以及类似的丑陋变通方法。有更好的方法吗?
(Apparently, Spring has NestedRuntimeException.contains(Class), which does what I want - but I'm not using Spring.)
(显然,Spring 有NestedRuntimeException.contains(Class),它做我想要的 - 但我没有使用 Spring。)
CLOSED:OK, I guess there's really no getting around a utility method :-) Thanks to everybody who replied!
关闭:好的,我想真的没有绕过实用方法:-) 感谢所有回复的人!
采纳答案by Tom Hawtin - tackline
Why would you want to avoid getCause
. You can, of course, write yourself a method to perform the task, something like:
为什么要避免getCause
. 当然,您可以自己编写一个方法来执行任务,例如:
public static boolean isCause(
Class<? extends Throwable> expected,
Throwable exc
) {
return expected.isInstance(exc) || (
exc != null && isCause(expected, exc.getCause())
);
}
回答by Mark
I don't think you have any choice but to call through the layers of getCause. If you look at the source code for the Spring NestedRuntimeException that you mention that is how it is implemented.
我认为你别无选择,只能通过 getCause 的层级调用。如果您查看您提到的 Spring NestedRuntimeException 的源代码,这就是它的实现方式。
回答by bruno conde
Well, I think there's no way to do this without calling getCause()
. It you think it's ugly implement a utilityclass for doing this:
好吧,我认为没有调用getCause()
. 如果您认为执行此操作的实用程序类很丑陋:
public class ExceptionUtils {
public static boolean wasCausedBy(Throwable e, Class<? extends Throwable>) {
// call getCause() until it returns null or finds the exception
}
}
回答by Bob Cross
Imitation is the sincerest form of flattery. Based on a quick inspection of the source, this is exactly what NestedRuntimeException does:
模仿是最真诚的奉承。 基于对源的快速检查,这正是 NestedRuntimeException 所做的:
/**
* Check whether this exception contains an exception of the given type:
* either it is of the given class itself or it contains a nested cause
* of the given type.
* @param exType the exception type to look for
* @return whether there is a nested exception of the specified type
*/
public boolean contains(Class exType) {
if (exType == null) {
return false;
}
if (exType.isInstance(this)) {
return true;
}
Throwable cause = getCause();
if (cause == this) {
return false;
}
if (cause instanceof NestedRuntimeException) {
return ((NestedRuntimeException) cause).contains(exType);
}
else {
while (cause != null) {
if (exType.isInstance(cause)) {
return true;
}
if (cause.getCause() == cause) {
break;
}
cause = cause.getCause();
}
return false;
}
}
CAVEAT: The above is the code as of 4 March 2009 so, if you really want to know what Spring is doing right now, you should research the code as it exists today (whenever that is).
警告:以上是 2009 年 3 月 4 日的代码,因此,如果您真的想知道 Spring 现在在做什么,您应该研究当前存在的代码(无论何时)。
回答by emannuelbs
You can do this using guava:
您可以使用番石榴做到这一点:
FluentIterable.from(Throwables.getCausalChain(e))
.filter(Predicates.instanceOf(ConstraintViolationException.class))
.first()
.isPresent();
回答by Patrick Boos
If you are using Apache Commons Lang, then you can use the following:
如果您使用的是Apache Commons Lang,那么您可以使用以下内容:
(1) When the cause should be exactly of the specified type
(1) 当原因应该完全是指定的类型时
if (ExceptionUtils.indexOfThrowable(exception, ExpectedException.class) != -1) {
// exception is or has a cause of type ExpectedException.class
}
(2) When the cause should be either of the specified type or its subclass type
(2) 当原因应该是指定类型或其子类类型时
if (ExceptionUtils.indexOfType(exception, ExpectedException.class) != -1) {
// exception is or has a cause of type ExpectedException.class or its subclass
}
回答by Nagy Attila
Based on Patrick Boos answer: If you using Apache Commons Lang 3 you can check:
基于 Patrick Boos 的回答:如果您使用 Apache Commons Lang 3,您可以检查:
indexOfThrowable: Returns the (zero based) index of the first Throwable that matches the specified class (exactly) in the exception chain. Subclasses of the specified class do not match
indexOfThrowable:返回异常链中与指定类(完全匹配)匹配的第一个 Throwable 的(从零开始的)索引。指定类的子类不匹配
if (ExceptionUtils.indexOfThrowable(e, clazz) != -1) {
// your code
}
or
或者
indexOfType: Returns the (zero based) index of the first Throwable that matches the specified class or subclassin the exception chain. Subclasses of the specified class do match
indexOfType:返回与异常链中指定的类或子类匹配的第一个 Throwable 的(从零开始的)索引。指定类的子类匹配
if (ExceptionUtils.indexOfType(e, clazz) != -1) {
// your code
}
Example for multiple types with Java 8:
Java 8 多种类型的示例:
Class<? extends Throwable>[] classes = {...}
boolean match = Arrays.stream(classes)
.anyMatch(clazz -> ExceptionUtils.indexOfType(e, clazz) != -1);