Java 异常未捕获?

2022-08-31 07:01:09

我有一个关于尝试捕获结构的小理论问题。

我昨天参加了一个关于Java的实践考试,我不明白下面的例子:

try {
    try {
        System.out.print("A");
        throw new Exception("1");
    } catch (Exception e) {
        System.out.print("B");
        throw new Exception("2");
    } finally {
        System.out.print("C");
        throw new Exception("3");
    }
} catch (Exception e) {
    System.out.print(e.getMessage());
}

问题是“输出会是什么样子?

我很确定它会是AB2C3,但令人惊讶的惊喜,这不是真的。

正确的答案是ABC3(经过测试,真的是这样)。

我的问题是,异常(“2”)去哪儿了?


答案 1

来自 Java 语言规范 14.20.2.

如果 catch 块由于原因 R 而突然完成,则执行最终块。然后有一个选择:

  • 如果最终块正常完成,则 try 语句由于原因 R 而突然完成。

  • 如果由于原因 S 而最终的块突然完成,则 try 语句由于原因 S 而突然完成(并且原因 R 被丢弃)。

因此,当存在引发异常的 catch 块时:

try {
    // ...
} catch (Exception e) {
    throw new Exception("2");
}

但也有一个最终的块也抛出一个异常:

} finally {
    throw new Exception("3");
}

Exception("2")将被丢弃,并且只会被传播。Exception("3")


答案 2

在 中引发的异常最终会阻止在 try 或 catch 块中较早抛出的异常。

Java 7 示例:http://ideone.com/0YdeZo

Javadoc的例子中:


static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

但是,在此示例中,如果方法 readLine 并关闭两个抛出异常,则方法 readFirstLineFromFileWithFinallyBlock 将引发从 finally 块引发的异常;从 try 块引发的异常被抑制。


Java 7 的新语法增加了异常抑制的另一个步骤:在 try 块中引发的异常会抑制在 try-with 部分中较早抛出的异常。try-with

来自同一示例:

try (
        java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
        java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    ) {
        for (java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) {
            String newLine = System.getProperty("line.separator");
            String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;
            writer.write(zipEntryName, 0, zipEntryName.length());
        }
    }

可以从与 try-with-resources 语句关联的代码块中引发异常。在上面的示例中,可以从 try 块引发异常,并且当它尝试关闭 ZipFile 和 BufferedWriter 对象时,try-with-resources 语句最多可以引发两个异常。如果从 try 块引发异常,并且从 try-with-resources 语句引发一个或多个异常,则从 try-with-resources 语句引发的那些异常将被抑制,并且该块引发的异常是由 writeToFileZipFileContents 方法引发的异常。可以通过从 try 块引发的异常中调用 Throwable.getSuppressed 方法来检索这些被禁止的异常。


在有问题的代码中,每个块都明显地丢弃了旧的异常,甚至没有记录它,当你试图解决一些错误时,这是不好的:

http://en.wikipedia.org/wiki/Error_hiding