197. Java 异常 - Suppressed Exceptions:捕捉多个异常并保留它们
🧠 什么是 Suppressed Exceptions?
在 Java 的 try-with-resources 语法中,当多个异常同时发生时,JVM 会选择抛出其中一个异常,并将其他异常作为 “抑制的异常(suppressed exceptions)” 保存起来。这些被抑制的异常不会立刻抛出,但可以通过调用 Throwable.getSuppressed() 方法来访问。
🔍 如何抑制异常?
假设我们在 try-with-resources 语句中有多个资源,且其中某些资源的关闭操作可能抛出异常。如果 try 块本身也抛出了一个异常,那么关闭资源时抛出的异常会被“抑制”,并不会直接抛出。取而代之的是,try 块抛出的异常会作为主异常,其他异常会被抑制。
示例:
public static void writeToFileZipFileContents(String zipFileName, String outputFileName) throws IOException {
Charset charset = StandardCharsets.US_ASCII;
Path outputFilePath = Paths.get(outputFileName);
try (
ZipFile zf = new ZipFile(zipFileName);
BufferedWriter writer = Files.newBufferedWriter(outputFilePath, charset)
) {
for (Enumeration<? extends ZipEntry> entries = zf.entries(); entries.hasMoreElements();) {
String entryName = entries.nextElement().getName() + System.lineSeparator();
writer.write(entryName);
}
} catch (IOException e) {
// 处理主要异常
System.err.println("Exception occurred: " + e.getMessage());
// 查看抑制的异常
Throwable[] suppressedExceptions = e.getSuppressed();
for (Throwable suppressed : suppressedExceptions) {
System.err.println("Suppressed: " + suppressed.getMessage());
}
throw e; // 重新抛出主异常
}
}
🔑 关键点
- 主异常:在
try块中抛出的异常是“主异常”,最终会被抛出。 - 抑制异常:如果在
try-with-resources语句中有多个资源关闭时抛出异常,这些异常会被抑制。 - 获取抑制异常:你可以通过
Throwable.getSuppressed()方法来访问抑制的异常,查看它们的详细信息。
🧑🏫 示例:
- 自定义两个资源
MyResource,它们在close()时都会抛异常; - 在
try块中也手动抛一个异常; - 最终看看 主异常 和 抑制异常 是如何表现的。
class MyResource implements AutoCloseable {
private final String name;
public MyResource(String name) {
this.name = name;
}
@Override
public void close() throws Exception {
throw new Exception("Error while closing resource: " + name);
}
}
public class SuppressedExceptionDemo {
public static void main(String[] args) {
try (
MyResource res1 = new MyResource("Resource-1");
MyResource res2 = new MyResource("Resource-2")
) {
// 在 try 块里抛出一个异常
throw new Exception("Main exception from try block");
} catch (Exception e) {
System.err.println("Caught main exception: " + e.getMessage());
// 打印被抑制的异常
Throwable[] suppressed = e.getSuppressed();
for (Throwable t : suppressed) {
System.err.println("Suppressed: " + t.getMessage());
}
}
}
}
说明:
-
主异常 是
Main exception from try block,它来自try块内部。 -
抑制的异常 来自
close()方法,这里有两个资源要关闭,所以两个异常被“抑制”了。 -
Java 保证了 try 块里的异常优先,其他异常不会丢失,而是通过
getSuppressed()保存。
🚀 总结:
- 在 try-with-resources 中,多个异常可以同时发生。
- 如果
try块抛出了异常,其他来自资源关闭的异常会被抑制。 - 抑制的异常 可以通过
getSuppressed()方法访问,帮助我们进行更全面的异常调试。
🧠 讲解小贴士:
- “在处理资源关闭时,虽然多个异常可能同时发生,但我们可以通过
getSuppressed()获取所有相关的异常。这样,即使程序继续执行,我们仍然能了解所有发生的问题。” - “确保你在捕获并处理主异常时,也关注抑制的异常。这有助于你全面了解代码执行中的所有异常。”