假设我有一个可能因检查异常而失败的方法(根据Sun的建议检查,因为它是可恢复的)。 此方法失败,并触发恢复策略。 但是初始方法和恢复策略都失败了。
在某些情况下,我可能想要两个堆栈跟踪,以便我知道为什么初始策略和恢复策略都失败了,而不仅仅是最后一个。
我该怎么办? 我应该创建一个CompositeException类型或类似的东西?这是一个好习惯吗?
答案 0 :(得分:5)
Java 7引入了抑制异常的概念。例如,try-with-resources语句是specified by:
资源以与初始化资源相反的顺序关闭。仅当资源初始化为非空值时才关闭资源。关闭一个资源的例外不会阻止关闭其他资源。如果先前由初始化程序,try块或资源关闭抛出异常,则会抑制此类异常。
和
如果资源的初始化正常完成,并且try块由于抛出值V而突然完成,那么:
- 如果由于抛出值V2而导致资源的自动关闭突然完成,则try-with-resources语句突然完成,因为抛出值V并将V2添加到V的抑制例外列表中< / LI>
这使用java.lang.Throwable.addSuppressedException,其javadoc为:
将指定的异常附加到为了传递此异常而被抑制的异常。此方法是线程安全的,通常由try-with-resources语句调用(自动和隐式)。
除非通过构造函数禁用,否则将启用抑制行为。禁用抑制时,此方法除了验证其参数外什么都不做。
请注意,当一个异常导致另一个异常时,通常会捕获第一个异常,然后在响应中抛出第二个异常。换句话说,两个例外之间存在因果关系。相反,在某些情况下,可以在兄弟代码块中抛出两个独立的异常,特别是在try-with-resources语句的try块和编译器生成的finally块中,它关闭资源。在这些情况下,只能传播一个抛出的异常。在try-with-resources语句中,当存在两个此类异常时,将传播源自try块的异常,并将finally块中的异常添加到由try块中的异常抑制的异常列表中。作为异常展开堆栈,它可以累积多个抑制异常。
异常可能会抑制异常,同时也会由另一个异常引起异常。异常是否具有原因在创建时在语义上是已知的,不像异常是否会抑制通常仅在抛出异常之后确定的其他异常。
请注意,程序员编写的代码也能够利用在有多个兄弟异常的情况下调用此方法,并且只能传播一个。
最后一段似乎适用于您的情况。所以你可以这样做:
public static void main(String[] args) throws Exception {
try {
throw new RuntimeException("Not now!");
} catch (Exception e) {
try {
tryAgain();
} catch (Exception e2) {
e.addSuppressed(e2);
throw e;
}
}
}
然后,堆栈跟踪将包含两个例外:
Exception in thread "main" java.lang.RuntimeException: Not now!
at tools.Test.main(Test.java:12)
Suppressed: java.lang.RuntimeException: I'm on holiday.
at tools.Test.tryAgain(Test.java:7)
at tools.Test.main(Test.java:15)
但调用者只能捕获主要异常。
答案 1 :(得分:0)
我会考虑初始方法失败时的异常,以及恢复策略失败时的异常。
在抛出恢复失败的异常(例如,发生超时时重试和失败)之前,您可能需要多次尝试恢复策略。
似乎保持初始方法和恢复策略异常分离是有意义的,因为它们代表两种不同的场景。
答案 2 :(得分:0)
不幸的是,Java Exception
只有一个原因,因此CompositeException
可能是您的最佳选择。但是,可以覆盖printStackTrace
方法以打印复合异常的堆栈跟踪:
public class CompositeException extends Exception {
private final List<Throwable> causes = new ArrayList<Throwable>();
public CompositeException(Throwable... causes) {
this.causes.addAll(Arrays.asList(causes));
}
// Other constructors you want
@Override
public void printStackTrace() {
if (causes.isEmpty()) {
super.printStackTrace();
return;
}
for (Throwable cause : causes) {
cause.printStackTrace();
}
}
@Override
public void printStackTrace(PrintStream s) {
if (causes.isEmpty()) {
super.printStackTrace(s);
return;
}
for (Throwable cause : causes) {
cause.printStackTrace(s);
}
}
@Override
public void printStackTrace(PrintWriter s) {
if (causes.isEmpty()) {
super.printStackTrace(s);
return;
}
for (Throwable cause : causes) {
cause.printStackTrace(s);
}
}
}
这是关于在一个例外中有多个原因异常所能做的所有事情。使用它:
CompositeException ce = new CompositeException(ex1, ex2, ex3);
然后ce.printStackTrace()
将打印所有3个异常的堆栈跟踪。