[英]Java exception not caught?
我對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”)去了哪里?
來自Java語言規范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")
。
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();
}
}
但是,在此示例中,如果方法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-with-resources語句關聯的代碼塊中拋出異常。 在上面的示例中,可以從try塊拋出異常,並且當try-with-resources語句嘗試關閉ZipFile和BufferedWriter對象時,最多可以拋出兩個異常。 如果從try塊拋出異常並且從try-with-resources語句拋出了一個或多個異常,那么從try-with-resources語句拋出的那些異常將被抑制,並且塊拋出的異常是這是由writeToFileZipFileContents方法拋出的。 您可以通過從try塊拋出的異常中調用Throwable.getSuppressed方法來檢索這些抑制的異常。
在問題的代碼中,每個塊明顯地丟棄舊的異常,甚至沒有記錄它,當你試圖解決一些錯誤時不好:
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
}
您的問題非常明顯,答案很簡單。 消息為“2”的Exception對象被Exception對象覆蓋,消息為“3”。
說明:當發生異常時,拋出其對象以捕獲要處理的塊。 但是當catch塊本身發生異常時,其對象將被轉移到OUTER CATCH Block(如果有)以進行異常處理。 同樣的事發生在這里。 帶有消息“2”的異常對象被傳送到OUTER catch Block。 但是等等 ..在離開內部的try-catch塊之前,它已經執行了最終。 這里發生了我們關注的變化。 拋出一個新的EXCEPTION對象(帶有消息“3”)或者這個finally塊替換已經拋出的Exception對象(帶有消息“2”)。結果,當打印出Exception對象的消息時,我們得到了被覆蓋的值即“3”而不是“2”。
記住:CATCH塊只能處理一個異常對象。
finally
塊總是運行。 要么從try塊內部return
,要么拋出異常。 finally
塊中拋出的異常將覆蓋catch分支中拋出的異常。
此外,拋出異常不會導致任何輸出。 該行throw new Exception("2");
不會寫任何東西。
根據你的代碼:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.