美文网首页
try catch finally 执行顺序

try catch finally 执行顺序

作者: FTOLsXD | 来源:发表于2018-07-05 13:35 被阅读35次

    在网上看到一些异常处理的面试题,试着总结一下,先看下面代码,把这个方法在main中进行调用打印返回结果,看看结果输出什么。

     public static  int testBasic(){
           int i = 1; 
           try{
               i++;
               System.out.println("try block, i = "+i);
           }catch(Exception e){
               i ++;
               System.out.println("catch block i = "+i);
           }finally{
               i = 10;
               System.out.println("finally block i = "+i);
           }
           return i;
    }
    

    没错,会按照顺序执行,先执行try内代码段,没有异常的话进入finally,最后返回,那么输出如下:

    try block, i = 2
    finally block i = 10
    main test i = 10

    这个没有问题,如果我们把return语句放入try catch里又会怎么样呢?

    public static  int testBasic(){
           int i = 1; 
           try{
               i++;
               System.out.println("try block, i = "+i);
               return i;
           }catch(Exception e){
               i ++;
               System.out.println("catch block i = "+i);
               return i;
           }finally{
               i = 10;
               System.out.println("finally block i = "+i);
           }
    }
    

    输出结果是:

    try block, i = 2
    finally block i = 10
    main test i = 2

    代码顺序执行从try到finally,由于finally是无论如何都会执行的,所以try里的语句并不会直接返回。在try语句的return块中,return返回的引用变量并不是try语句外定义的引用变量i,而是系统重新定义了一个局部引用i’,这个引用指向了引用i对应的值,也就是2,即使在finally语句中把引用i指向了值10,因为return返回的引用已经不是i,而是i',所以引用i的值和try语句中的返回值无关了。

    但是,这只是一部分,如果把i换成包装类型而不是基本类型呢,来看看输出结果怎样,示例如下:

    public static  List<Object> testWrap(){
           List<Object> list = new ArrayList<>();
           try{
               list.add("try");
               System.out.println("try block");
               return list;
           }catch(Exception e){
               list.add("catch");
               System.out.println("catch block");
               return list;
           }finally{
               list.add("finally");
               System.out.println("finally block ");
           }
    }
    

    打印结果如下:

    try block
    finally block
    main test i = [try, finally]

    可以看到,finally里对list集合的操作生效了,这是为什么呢。我们知道基本类型在栈中存储,而对于非基本类型是存储在堆中的,返回的是堆中的地址,因此内容被改变了。

    好了,现在我们在finally里加一个return,看看语句是从哪里返回的。

    public static  int testBasic(){
           int i = 1; 
           try{
               i++;
               System.out.println("try block, i = "+i);
               return i;
           }catch(Exception e){
               i ++;
               System.out.println("catch block i = "+i);
               return i;
           }finally{
               i = 10;
               System.out.println("finally block i = "+i);
               return i;
           }
    }
    

    输出结果如下:

    try block, i = 2
    finally block i = 10
    main test i = 10

    可以看到,是从finally语句块中返回的。可见,JVM是忽略了try中的return语句。但IDE中会对finally中加的return有黄色警告提示,这是为什么呢,在try里加入一行会执行异常的代码,如下:

    public static  int testBasic(){
           int i = 1; 
           try{
               i++;
               int m = i / 0 ;
               System.out.println("try block, i = "+i);
               return i;
           }catch(Exception e){
               i ++;
               System.out.println("catch block i = "+i);
               return i;
           }finally{
               i = 10;
               System.out.println("finally block i = "+i);
               return i;
           }
    }
    

    打印结果如下:

    catch block i = 3
    finally block i = 10
    main test i = 10

    可以看到,因为finally中有return语句,try、catch中的异常被消化掉了,屏蔽了异常的发生,这与初期使用try、catch的初衷是相违背的,因此编译器也会提示警告。

    那如果在finally中有异常发生,会对try、catch中的异常有什么影响呢?

    public static  int testBasic(){
           int i = 1; 
           try{
               i++;
               Integer.parseInt(null);
               System.out.println("try block, i = "+i);
               return i;
           }catch(Exception e){
               String.valueOf(null);
               System.out.println("catch block i = "+i);
               return i;
           }finally{
               i = 10;
               int m = i / 0;
               System.out.println("finally block i = "+i);
           }
    }
    

    这里我们在try、catch里强行加上异常语句,打印结果如下:

    Exception in thread "main" java.lang.ArithmeticException: / by zero
    at tryandcatch.TryAndCatch.testBasic(TryAndCatch.java:25)
    at tryandcatch.TryAndCatch.main(TryAndCatch.java:45)

    这个提示表示的是finally里的异常信息,也就是说一旦finally里发生异常,try、catch里的异常信息即被消化掉了,也达不到异常信息处理的目的。

    总结以上测试:

    1、finally语句总会执行

    2、如果try、catch中有return语句,finally中没有return,那么在finally中修改除包装类型和静态变量、全局变量以外的数据都不会对try、catch中返回的变量有任何的影响(包装类型、静态变量会改变、全局变量)

    3、尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生

    4、finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略

    所以在实际项目中,finally常常是用来关闭流或者数据库资源的,并不额外做其他操作。

    注意String new 和 "" 是不一样的。

    1.String str1 = "abc";

    String str2 = "abc";

    sysout(str1==str2) 为 TRUE

    解释:栈中str1和str2都直接指向常量池中“abc”,==比较地址,地址一样。

    String str1 = "abc";

    String str2 = new String(“abc”);

    sysout(str1==str2);为FALSE

    解释:str1指向常量池中“abc”,str2指向堆中新开辟的空间,所以地址不一样。

    String str1 = "abc";

    Stirng str2 = “ab”;

    str2=str2+“c”;

    sysout(str1==str2);为FALSE

    解释:str1指向常量池“abc”,str2指向堆中新开辟的空间,故地址不同。

    String str1 = new String(“abc”);

    String str2 = new String(“abc”);

    sysout(str1==str2);为FALSE

    解释:str1指向堆中开辟的空间,str2在堆中又重新开辟了空间,两者并不是同一个空间,故地址不同。

    相关文章

      网友评论

          本文标题:try catch finally 执行顺序

          本文链接:https://www.haomeiwen.com/subject/oqcpuftx.html