一般来说,当我们以某种方式并行执行可能产生异常的情况下,应使用Throwable addSuppressed()方法,而抑制。我找到了 2 个例子;
在了解详细信息之前,正如@sarelbotha 所说,就我而言,我只需要继续包装原始异常作为新异常的原因。
try-finally 块中的默认行为,我们有 2 个异常,原始异常被抑制,我们只看到 finally 块中的异常。如果我们使用 finally 块来关闭资源,而不是我们真的想看到原始异常,但我们也可以选择看到 finally 块中的异常,它关闭了我们的资源并失败了。
从第 7 版开始,平台支持抑制异常的概念(与 try-with-resources 语句一起使用)。为了传递异常而被抑制的任何异常都将打印在堆栈跟踪下方。
http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#printStackTrace%28%29
第一个应该阅读有关 try-with-resource 新功能的信息。例如,您可以在这里阅读它http://www.baptiste-wicht.com/2010/08/java-7-try-with-resources-statement/ 或在这里What is the Java 7 try-with-resources bytecode equivalent using try-catch-finally?。简而言之,在某种意义上,您可以并行拥有 2 个 Throwable,通常来自 try 块和 finally 块。旧的 try-catch 语义将从 finally 块返回异常,而 try 块中的 suppressed 异常(或从 catch 块中重新抛出异常)。新的 try-with-resource 功能使您能够同时获得异常。更重要的是,您将收到原始异常,其中 finally 块中的异常将被抑制
请注意,当一个异常导致另一个异常时,通常会捕获第一个异常,然后抛出第二个异常作为响应。换句话说,这两个例外之间存在因果关系。相反,在同级代码块中可能会引发两个独立异常的情况,特别是在 try-with-resources 语句的 try 块和关闭资源的编译器生成的 finally 块中。在这些情况下,只能传播引发的异常之一。在 try-with-resources 语句中,当有两个这样的异常时,将传播源自 try 块的异常,并将 finally 块的异常添加到由 try 块的异常抑制的异常列表中。当一个异常展开堆栈时,它可以累积多个被抑制的异常。
示例:
public class TestClass {
static class ResourceA implements AutoCloseable{
public void read() throws Exception{
throw new Exception("ResourceA read exception");
}
@Override
public void close() throws Exception {
throw new Exception("ResourceA close exception");
}
};
static class ResourceB implements AutoCloseable{
public void read() throws Exception{
throw new Exception("ResourceB read exception");
}
@Override
public void close() throws Exception {
throw new Exception("ResourceB close exception");
}
};
//a test method
public static void test() throws Exception{
try (ResourceA a = new ResourceA();
//ResourceB b = new ResourceB()
) {
a.read();
//b.read();
} catch (Exception e) {
throw e;
}
}
public static void main(String[] args) throws Exception {
test();
}
}
输出如下:
Exception in thread "main" java.lang.Exception: ResourceA read exception
at TestClass$ResourceA.read(TestClass.java:6)
at TestClass.test(TestClass.java:29)
at TestClass.main(TestClass.java:39)
Suppressed: java.lang.Exception: ResourceA close exception
at TestClass$ResourceA.close(TestClass.java:10)
at TestClass.test(TestClass.java:31)
... 1 more
批处理作业(批量操作)。
好吧,我在 try-with-resources 之外发现了这种方法的一些用法。下面是来自java.net.URLClassLoader.close的源代码
public void close() throws IOException {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(new RuntimePermission("closeClassLoader"));
}
List<IOException> errors = ucp.closeLoaders();
// now close any remaining streams.
synchronized (closeables) {
Set<Closeable> keys = closeables.keySet();
for (Closeable c : keys) {
try {
c.close();
} catch (IOException ioex) {
errors.add(ioex);
}
}
closeables.clear();
}
if (errors.isEmpty()) {
return;
}
IOException firstex = errors.remove(0);
// Suppress any remaining exceptions
for (IOException error: errors) {
**firstex.addSuppressed(error);**
}
throw firstex;
}
一般来说,这种方法可以用于批处理作业(批量操作),当我们应该继续下一个项目(如本例中那样关闭下一个打开的流)时,无论操作是否在当前项目成功与否。这样一来,正如我之前所说,我们以某种方式并行执行会产生异常,即抑制。在这种情况下,我们应该使用上面的方法来抛出异常,并在其中保留被抑制的异常。