我对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());
}
问题是“输出会是什么样子?”
我很确定它会是AB2C3,但令人惊讶的是,这不是真的。
正确答案是ABC3(经过测试,确实就是这样)。
我的问题是,例外(“2”)去了哪里?
答案 0 :(得分:196)
来自Java Language Specification 14.20.2.:
如果catch块由于原因R突然完成,则执行finally块。然后有一个选择:
如果finally块正常完成,则try语句突然完成,原因为R。
如果finally块因原因S而突然完成,则try语句突然完成,原因为S(并且原因R被丢弃)。
所以,当有一个引发异常的catch块时:
try {
// ...
} catch (Exception e) {
throw new Exception("2");
}
但是还有一个finally块也会引发异常:
} finally {
throw new Exception("3");
}
Exception("2")
将被丢弃,只会传播Exception("3")
。
答案 1 :(得分:19)
finally块中抛出的异常会抑制先前在try或catch块中抛出的异常。
Java 7示例:http://ideone.com/0YdeZo
来自Javadoc's示例:
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和close都抛出 异常,然后方法readFirstLineFromFileWithFinallyBlock 抛出finally块抛出的异常;例外 从try块抛出的内容被抑制。
Java 7的新try-with
语法增加了另一个异常抑制步骤: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());
}
}
可以从与之关联的代码块中抛出异常 尝试使用资源声明。在上面的例子中,一个例外可以 从try块抛出,最多可以抛出两个异常 从try-with-resources语句尝试关闭时 ZipFile和BufferedWriter对象。如果抛出异常 尝试阻止,并从中抛出一个或多个异常 try-with-resources语句,然后抛出那些异常 try-with-resources语句被抑制,并抛出异常 块是被抛出的块 writeToFileZipFileContents方法。你可以检索这些被抑制的 从中调用Throwable.getSuppressed方法的异常 try块抛出的异常。
在问题的代码中,每个块都明显地丢弃旧的异常,甚至没有记录它,当你试图解决一些错误时不好:
答案 2 :(得分:9)
由于throw new Exception("2");
阻止了catch
而不是try
,因此不再会被抓住。
请参阅14.20.2. Execution of try-finally and 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
}
答案 3 :(得分:5)
您的问题非常明显,答案很简单。 消息为“2”的异常对象被异常对象覆盖,消息为“3”。
说明: 当发生异常时,它抛出的对象会捕获块来处理。但是当catch块本身发生异常时,其对象将被转移到OUTER CATCH Block(如果有)以进行异常处理。同样的事发生在这里。带有消息“2”的异常对象被传送到OUTER catch Block。 但是等等 ..在离开内部try-catch块之前,它已经执行了最终。这里发生了我们关注的变化。抛出一个新的EXCEPTION对象(带有消息“3”)或者这个finally块替换已经抛出的Exception对象(带有消息“2”)。结果,当打印出Exception对象的消息时,我们得到了被覆盖的值即“3”而不是“2”。
记住:CATCH块上只能处理一个异常对象。
答案 4 :(得分:2)
finally
块始终运行。您可以从try块内部return
或抛出异常。 finally
块中抛出的异常将覆盖catch分支中抛出的异常。
此外,抛出异常不会导致任何输出。第throw new Exception("2");
行不会写出任何内容。
答案 5 :(得分:0)
根据你的代码:
try {
try {
System.out.print("A");
throw new Exception("1"); // 1
} catch (Exception e) {
System.out.print("B"); // 2
throw new Exception("2");
} finally { // 3
System.out.print("C"); // 4
throw new Exception("3");
}
} catch (Exception e) { // 5
System.out.print(e.getMessage());
}
正如你在这里看到的那样:
# 1
; B - # 2
; # 3
在try-catch之后执行(或者只尝试,如果没有发生任何异常)语句并打印C - # 4
并抛出新的异常; # 5
; 结果是ABC3
。 2
与1