java中finally語句塊注意事項

 我在程序中使用TarArchiveOutputStream對多個文件進行打包,finally語句塊中調用了它的close方法關閉輸出流。昨天碰到了一個很詭異的問題,執行到finally語句塊拋出異常。按正常處理邏輯,文件打包會正常完成,finally中是不會出現異常的。然後就開始定位爲什麼會出現這樣的異常,最終發現是因爲打包過程中進行了額外的檢查,如果條件不符合就拋出異常,然後進入到finally語句塊。因爲打包被異常中斷,導致close出現異常,而finally中的異常會覆蓋try語句中的異常,這就是我們定位這個文件花了較長時間的原因。我們用一個簡單的測試代碼來重現和說明這個現象:
1. public class Test {
2.     public static void main(String[] args) {
3.         int x = 1;
4.         int y = 0;
5.         int z;
6.         try {
7.             z = (100 * x) / y;
8.             System.out.println("z=" + z);
9.         } finally {
10.             z = x / y;
11.             System.out.println("z=" + z);
12.         }
13.     }
14. }
可以看到第7行和第10行都會出現被0除的異常。
執行以上代碼的輸出結果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Test.main(Test.java:10)
可以看到沒有打印出第7行拋出異常時的調用堆棧。這是爲什麼呢?
第7行拋出異常後,進入第9行開始的finally語句塊,finally語句塊中的第10行也出現了異常,導致前面的異常被覆蓋掉,因此最後打印出的異常調用堆棧是第10行的。
解決方法,捕獲finally中可能出現的異常,修改後代碼爲:
1. public class Test {
2.     public static void main(String[] args) {
3.         int x = 1;
4.         int y = 0;
5.         int z;
6.         try {
7.             z = (100 * x) / y;
8.             System.out.println("z=" + z);
9.         } finally {
10              try {
11.                 z = x / y;
12.                 System.out.println("z=" + z);
13.              } catch(Exception ex) {
14.                  ex.printStackTrace();
15.              }
16.         }
17.     }
18. }

執行時的輸出爲:
java.lang.ArithmeticException: / by zero
        at Test.main(Test.java:11)
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Test.main(Test.java:7)
可見,這時try語句中的異常信息也出來了。

總結一下,finally中的語句,如果可能出現異常,一定要catch。
另外一個規範的做法,不要在finally中return一個返回值。具體原因是什麼,請各位仔細思考一下,相信會想明白的
發佈了7 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章