我所理解的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的值是不会变的(要么是基础数据类型的值,要么是内存空间的地址值)。若是有兴趣反编译的话,能够验证。

相关文章
相关标签/搜索