記錄一些關於try-catch-finally的使用:java
1,try{}中若是沒有發生異常,catch{}不會執行;app
try{}中若是發生異常,catch{}執行;
不管try{}是否發生異常,finally{}都會執行。this
public class TestFinally { public static void main(String[] args) { TestFinally testFinally = new TestFinally(); testFinally.tryCauseExceptionMethod(); System.out.println("========================"); testFinally.tryNotCauseExceptionMethod(); } private void tryCauseExceptionMethod(){ try{ System.out.println("try start"); int a = 1 / 0; System.out.println("try end"); }catch(Exception e){ System.out.println("catch"); }finally{ System.out.println("finally"); } } private void tryNotCauseExceptionMethod(){ try{ System.out.println("try"); }catch(Exception e){ System.out.println("catch"); }finally{ System.out.println("finally"); } } }
控制檯輸出:線程
try start catch finally ======================== try finally
2,子類異常不會捕獲父類異常。父類異常能夠捕獲子類異常。code
try { int a = 1 / 0; } catch (MyFirstException e) { System.out.println("fist"); } class MyFirstException extends ArithmeticException{}
以上代碼沒法捕獲異常。對象
3,try、catch、finally中均可以拋出異常,無論是編譯器異常仍是運行期異常。繼承
若是try中拋出的異常能夠被catch捕獲,則try中拋出的該異常永遠不會被方法調用者捕獲。
若是catch中拋出了異常,catch的異常會正常拋出並打印,方法調用者能夠捕獲catch拋出的該異常。線程能夠正常執行。
若是finally中拋出異常,則至關於整個try-catch-finally拋出了異常。內存
public class TestMCatch { public static void main(String[] args) { TestMCatch testCatch = new TestMCatch(); try { testCatch.myCatch(); } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("cath the method throw"); } System.out.println("even exception happend, the thread still excute"); } private void myCatch() throws FileNotFoundException{ try { throw new FileNotFoundException("try throw exception"); } catch (Exception e) { System.out.println("catch try throw, msg: " + e.getMessage()); throw new FileNotFoundException("catch throw exception"); } } }
控制檯輸出:get
catch try throw, msg: try throw exception cath the method throw even exception happend, the thread still excute java.io.FileNotFoundException: catch throw exception at cn.testException.TestMCatch.myCatch(TestMCatch.java:30) at cn.testException.TestMCatch.main(TestMCatch.java:15)
4,多個catch{}中,catch是有順序關係的,且只能被捕獲一次。編譯器
若是異常具備繼承關係,則子類不能出如今父類後,不然編譯器不經過。
若是catch的異常彼此意見不具備繼承關係,則按照順序,先匹配的先執行。
(因爲java中只能是單繼承,因此全部catch中最近接異常的catch會被執行)
try { int a = 1 / 0; } catch (Exception e) { e.printStackTrace(); } catch (ArithmeticExceptione) { e.printStackTrace(); }
以上代碼編譯不經過。
try { int a = 1 / 0; } catch (ArithmeticException e) { System.out.println("the ArithmeticException catch");; } catch (Exception e) { System.out.println("the Exception catch");; }
控制檯輸出:
the ArithmeticException catch
5,catch中捕獲到異常後,可能再次throw,而且能夠把當前的Exception做爲構造參數傳遞,方法調用者捕獲後,e.printStackTrace(),控制檯會有Caused by 產生。
public class TestReturn { public static void main(String[] args) { TestReturn testReturn = new TestReturn(); try { int a = testReturn.testReturnMethod(); System.out.println(a); } catch (Exception e) { e.printStackTrace(); } } private int testReturnMethod(){ int a = 1; try { a = 1 / 0; return a; } catch (Exception e) { a = 9; throw new RuntimeException(e); } finally { a = 11; } } }
控制檯輸出:
java.lang.RuntimeException: java.lang.ArithmeticException: / by zero at cn.testException.TestReturn.testReturnMethod(TestReturn.java:26) at cn.testException.TestReturn.main(TestReturn.java:12) Caused by: java.lang.ArithmeticException: / by zero at cn.testException.TestReturn.testReturnMethod(TestReturn.java:22) ... 1 more
6,try-catch-finally與return結合的狀況,稍微複雜一些。
首先,方法中常常return的數據分爲3類:1.基礎數據類型;2.基礎數據類型對應的包裝類以及String這樣的JDK中原生支持的final類;3.其餘的普通的POJO類。
爲何要分爲這3類呢?1.對於基礎類型數據,在Java中調用的數據傳遞是值傳遞;2.對於Object類型,在Java中調用的數據傳遞是引用傳遞,傳遞的是內存空間的地址值。
那爲何還要分爲final和非final呢?由於final類的實例對象的地址值是不可更改的。好比:
Integer a = 0; // 堆空間中開闢一塊空間,並把new Integer(0)的引用賦給a Integer a = 1; // 堆空間中開闢一塊空間,並把new Integer(1)的引用賦給a,原來的new Integer(0)的空間等待被回收
正是由於Integer是final類的,它的改變是須要改變引用地址的。
但是這根本文討論的try-catch-finally有關係嗎?還真有。
6.1,若是finally中有return,則renturn的是finally中的數據。
public static void main(String[] args) { TestReturn testReturn = new TestReturn(); System.out.println(testReturn.testReturnMethod()); } private int testReturnMethod(){ int a = 1; try { a = 10; return a; } catch (Exception e) { a--; return a; } finally { a++; return a; } }
控制檯輸出: 11
6.2,若是finally中沒有return
6.2.1,若是try中有return,return的是基本數據類型,則finally中的修改不會對原return值改變。
public static void main(String[] args) { TestReturn testReturn = new TestReturn(); System.out.println(testReturn.testReturnMethod()); } private int testReturnMethod(){ int a = 1; try { a = 10; return a; } catch (Exception e) { a--; return a; } finally { a++; } }
控制檯輸出: 10
6.2.2,若是try中有return,return的是基本數據類型的包裝類以及String這樣的JDK中原生支持的final類,則finally中的修改不會原return值改變。
public static void main(String[] args) { TestReturn testReturn = new TestReturn(); System.out.println(testReturn.testReturnMethod()); } private String testReturnMethod(){ String a = "a"; try { a = "b"; return a; } catch (Exception e) { a = "c"; return a; } finally { a = "d"; } }
控制檯輸出: b
6.2.3,若是try中有return,return的是普通的POJO類型,這finally對該POJO的修改會影響原return的值。
public class TestReturn { public static void main(String[] args) { TestReturn testReturn = new TestReturn(); User u = new User("lily"); System.out.println(testReturn.testReturnMethod(u).getName()); } private User testReturnMethod(User u){ try { u.setName("try"); return u; } catch (Exception e) { return u; } finally { u.setName("finally"); } } } class User { private String name; public User(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
控制檯輸出:finally
6.3,總結:try中的retrun拿到最終要return的值,而後進入finally執行。只要finally中沒有return,不管finally如何更改,最終要return的值是不會變的(要麼是基礎數據類型的值,要麼是內存空間的地址值)。若是有興趣反編譯的話,能夠驗證。