我所理解的JDK異常(二):try-catch-finally的使用

記錄一些關於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的值是不會變的(要麼是基礎數據類型的值,要麼是內存空間的地址值)。若是有興趣反編譯的話,能夠驗證。

相關文章
相關標籤/搜索