没有抓到Java异常?

Kou*_*lik 170 java exception try-catch

我对try-catch构造有一个小的理论问题.

我昨天参加了一个关于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());
}
Run Code Online (Sandbox Code Playgroud)

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

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

正确的答案是ABC3(经过测试,确实就是这样).

我的问题是,例外("2")去了哪里?

Ada*_*ion 196

来自Java语言规范14.20.2.:

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

  • 如果finally块正常完成,则try语句突然完成,原因是R.

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

所以,当有一个引发异常的catch块时:

try {
    // ...
} catch (Exception e) {
    throw new Exception("2");
}
Run Code Online (Sandbox Code Playgroud)

但是还有一个finally块也会引发异常:

} finally {
    throw new Exception("3");
}
Run Code Online (Sandbox Code Playgroud)

Exception("2")将被丢弃,只会Exception("3")传播.

  • 这甚至适用于"return"语句.如果你的finally块有一个返回值,它将覆盖`try`或`catch`块中的任何返回值.由于这些"特性",一个好的做法是最终块应该**永远不会抛出异常或返回语句. (71认同)

S.D*_*.D. 19

finally块中抛出的异常会抑制先前在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,在此示例中,如果方法readLine和close都抛出异常,则方法readFirstLineFromFileWithFinallyBlock抛出finally块抛出的异常; 从try块抛出的异常被抑制.


try-withJava 7 的新语法增加了另一个异常抑制步骤:try块中抛出的异常会抑制try-with part中之前抛出的异常.

来自同一个例子:

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());
        }
    }
Run Code Online (Sandbox Code Playgroud)

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


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

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


Mar*_*oun 9

既然throw new Exception("2");是从catch块而不是被抛出try,它将不再被捕获.
14.20.2.执行try-finally和try-catch-finally.

这就是发生的事情:

try {
    try {
        System.out.print("A");         //Prints A
        throw new Exception("1");   
    } catch (Exception e) { 
        System.out.print("B");         //Caught from inner try, prints B
        throw new Exception("2");   
    } finally {
        System.out.print("C");         //Prints C (finally is always executed)
        throw new Exception("3");  
    }
} catch (Exception e) {
    System.out.print(e.getMessage());  //Prints 3 since see (very detailed) link
}
Run Code Online (Sandbox Code Playgroud)


Bha*_*rat 5

您的问题非常明显,答案在相同程度上也很简单。 消息为“ 2”的Exception对象被消息为“ 3”的Exception对象覆盖。

说明: 发生异常时,抛出它的对象以捕获块以进行处理。但是,当catch块本身发生异常时,其对象将转移到OUTER CATCH Block(如果有)以进行异常处理。同样发生在这里。消息为“ 2”的异常对象将传输到OUTER catch Block。但是,请等待 ..在离开内部try-catch块之前,它必须最终执行。这里发生了我们关注的变化。抛出了一个新的EXCEPTION对象(带有消息“ 3”),或者此finally块替换了已经抛出的Exception对象(带有消息“ 2”)。结果,当打印Exception对象的消息时,我们得到了覆盖值,即“ 3”而不是“ 2”。

请记住:CATCH块只能处理一个异常对象。