'try(A a = new A())' VS 'try finally'
- 2019 年 11 月 23 日
- 筆記
實現了AutoCloseable介面的類,可以在try的時候直接實例化對象。try程式碼塊完成之後,自動調用close方法,相當於在finally里主動調用。但是出現異常後的流程和try finally有什麼不同呢? 下面寫程式碼測試一下。
首先定義一個類Cat,實現AutoCloseable介面
class Cat implements AutoCloseable{ void sayHello() throws Exception { Utils.println("calling sayHello(), I will throw an exception"); throw new Exception("Exception in sayHello() "); } @Override public void close() throws Exception { Utils.println("I'm closing, I will throw an exception"); throw new Exception("Exception in close()"); } }
我們的這個Cat有以下特點:
- sayHello方法會拋出異常
- close方法也會拋出異常
test v1: 'try(Cat cat = new Cat())' VS 'try finally'
沒有catch(不要被外層的catch迷惑,那只是為了列印異常)
static void testV1(){ Utils.println("----try(Cat cat = new Cat())-----"); try{ try(Cat cat = new Cat()){ cat.sayHello(); } }catch (Exception e){ Utils.println("cache error in main (" + e + "), let's see its stack trace"); Utils.printStackTrace(e); } Utils.println("--------------"); Utils.println("----try finally-----"); try{ Cat cat = null; try{ cat = new Cat(); cat.sayHello(); }finally { if(cat != null){ cat.close(); } } }catch (Exception e){ Utils.println("cache error in main (" + e + "), let's see its stack trace"); Utils.printStackTrace(e); } Utils.println("--------------"); }
結果輸出:
----test v1---------------------------------------- ----try(Cat cat = new Cat())----- calling sayHello(), I will throw an exception I'm closing, I will throw an exception cache error in main (java.lang.Exception: Exception in sayHello() ), let's see its stack trace java.lang.Exception: Exception in sayHello() at Cat.sayHello(Cat.java:4) at Test.testV1(Test.java:16) at Test.main(Test.java:4) Suppressed: java.lang.Exception: Exception in close() at Cat.close(Cat.java:10) at Test.testV1(Test.java:17) ... 1 more -------------- ----try finally----- calling sayHello(), I will throw an exception I'm closing, I will throw an exception cache error in main (java.lang.Exception: Exception in close()), let's see its stack trace java.lang.Exception: Exception in close() at Cat.close(Cat.java:10) at Test.testV1(Test.java:33) at Test.main(Test.java:4) --------------
結論
- try(Cat cat = new Cat())
- try程式碼塊完成之後會自動調用close
- close拋出的異常,被Suppressed了,外層捕獲的只有sayHello的異常,但通過堆棧可以找到這個Suppressed的異常
- try finally
- 外層捕獲的是在finally執行close時拋出的異常,sayHello的異常完全不見了。
test v2: 'try(Cat cat = new Cat()) catch{}' VS 'try catch finally'
有catch,並且catch里再拋出異常
static void testV2(){ Utils.println("----try(Cat cat = new Cat()) catch-----"); try{ try(Cat cat = new Cat()){ cat.sayHello(); } catch (Exception e) { Utils.println("cached err (" + e.getMessage() + "), I will throw an exception again"); throw new Exception("Exception in catch", e); } }catch (Exception e){ Utils.println("cache error in main (" + e + "), let's see its stack trace"); Utils.printStackTrace(e); } Utils.println("-----------------------------------------"); Utils.println("----try catch finally--------------------"); try{ Cat cat = null; try{ cat = new Cat(); cat.sayHello(); } catch (Exception e) { Utils.println("cached err (" + e.getMessage() + "), I will throw an exception again"); throw new Exception("Exception in catch", e); }finally { if(cat != null){ cat.close(); } } }catch (Exception e){ Utils.println("cache error in main (" + e + "), let's see its stack trace"); Utils.printStackTrace(e); } Utils.println("-------------------------------------------"); }
結果輸出
----test v2------ ----try(Cat cat = new Cat()){} catch{}----- calling sayHello(), I will throw an exception I'm closing, I will throw an exception cached err (Exception in sayHello() ), I will throw an exception again cache error in main (java.lang.Exception: Exception in catch), let's see its stack trace java.lang.Exception: Exception in catch at Test.testV2(Test.java:50) at Test.main(Test.java:8) ----------------------------------------- ----try catch finally-------------------- calling sayHello(), I will throw an exception cached err (Exception in sayHello() ), I will throw an exception again I'm closing, I will throw an exception cache error in main (java.lang.Exception: Exception in close()), let's see its stack trace java.lang.Exception: Exception in close() at Cat.close(Cat.java:10) at Test.testV2(Test.java:70) at Test.main(Test.java:8) ------------------------------------------- ---------------------------------------------------------------------
結論
- try(Cat cat = new Cat()) catch
- catch之前就調用了close(符合try程式碼塊完成之後會自動調用close這個結論)
- catch到的是sayHello的異常,close拋出的異常依然被Suppressed了
- catch中再次拋出的異常被外層捕獲
- try catch finally
- 先走catch,再走finally,所以catch捕獲的是sayHello的異常
- catch中再次拋出的異常不見了,外層捕獲的是在finally執行close時拋出的異常。
測試程式碼地址:https://github.com/kongxiangxin/pine/tree/master/auto-closeable