zoukankan      html  css  js  c++  java
  • 有return的情况下try catch finally的执行顺序

    有这样一个问题,异常处理大家应该都不陌生,类似如下代码:

     1 public class Test {
     2     public static void main(String[] args) {
     3         int d1 = 0;
     4         int d2 = 1;
     5         try {
     6             d2--;
     7             d1 = 1 / d2;
     8             System.out.println("try");
     9         }catch (Exception e){
    10             System.out.println("Catch An Exception.");
    11         }finally {
    12             System.out.println("finally");
    13         }
    14     }
    15 }

    运行到第7行的时候,会出现算术异常,try语句块捕获到这个异常,然后开始执行catch语句块中的内容,最后执行,finally语句块中的内容,因此输出如下:

    Catch An Exception.
    finally

    但是,如果try,catch,finally语句中有return的时候,会怎样呢?

      我们都知道,finally语句块是不论如何都会执行的,那三个块中的return,会先返回谁呢?我们来进行一下测试:

     1 public class Test {
     2     public static void main(String[] args) {
     3         int i = Test.getReturn();
     4         System.out.println(i);
     5 
     6     }
     7 
     8     public static int getReturn(){
     9         int a = 0;
    10         int d1 = 0;
    11         int d2 = 1;
    12         try {
    13       //try语句块中没有发生异常
    14             a = 10;
    15             d1 = 1 / d2;
    16             return a;
    17         }catch (Exception e){
    18             a = 20;
    19             System.out.println("Catch An Exception.");
    20             return a;
    21         }finally {
    22             a = 30;
    23             System.out.println("finally");
    24             return a;
    25         }
    26     }
    27 }

    这里的try语句块中没有发生异常,那么执行顺序如何呢?在try中的return是直接返回吗?finally的return该怎样处理呢?先让我们看一下结果:

    finally
    30

    结果是执行完成finally语句块之后,使用的是finally语句块中的a,而不是try语句块中的a。

      那如果try中出现异常呢?我们改动一下:

     1 public class Test {
     2     public static void main(String[] args) {
     3         int i = getReturn();
     4         System.out.println(i);
     5 
     6     }
     7 
     8     public static int getReturn(){
     9         int a = 0;
    10         int d1 = 0;
    11         int d2 = 1;
    12         try {
    13             a = 10;
    14             d1 = 1 / (--d2);
    15             return a;
    16         }catch (Exception e){
    17             a = 20;
    18             System.out.println("Catch An Exception.");
    19             return a;
    20         }finally {
    21             a = 30;
    22             System.out.println("finally");
    23             return a;
    24         }
    25     }
    26 }

    好的,现在try中出现了算术异常,catch语句块将被执行,然后再执行finally语句块,这样的话返回结果如何呢?

    Catch An Exception.
    finally
    30

    还是返回30,也就是finally中a的值

      如果去掉finally中的return会怎样?

     1 public class Test {
     2     public static void main(String[] args) {
     3         int i = getReturn();
     4         System.out.println(i);
     5 
     6     }
     7 
     8     public static int getReturn(){
     9         int a = 0;
    10         int d1 = 0;
    11         int d2 = 1;
    12         try {
    13             a = 10;
    14             d1 = 1 / (--d2);
    15             return a;
    16         }catch (Exception e){
    17             a = 20;
    18             System.out.println("Catch An Exception.");
    19             return a;
    20         }finally {
    21             a = 30;
    22             System.out.println("finally");
    23             //return a;
    24         }
    25     }
    26 }

    输出如下:

    Catch An Exception.
    finally
    20

    返回的是catch语句块中的a。先执行catch语句块中的代码,finally语句虽然执行了,a的值应该也被修改成30了,但实际返回的却是20,。

      我们再来做一个测试,把catch和finally语句块中的return都注释掉,来看看返回情况:

     1 public class Test {
     2     public static void main(String[] args) {
     3         int i = getReturn();
     4         System.out.println(i);
     5 
     6     }
     7 
     8     public static int getReturn(){
     9         int a = 0;
    10         int d1 = 0;
    11         int d2 = 1;
    12         try {
    13             a = 10;
    14             d1 = 1 / (d2);
    15             return a;
    16         }catch (Exception e){
    17             a = 20;
    18             System.out.println("Catch An Exception.");
    19             //return a;
    20         }finally {
    21             a = 30;
    22             System.out.println("finally");
    23             //return a;
    24         }
    25         return a;
    26     }
    27 }

    输出如下:

    finally
    10

    所以finally中虽然修改了a的值,但实际返回的是修改之前的值。也就是相当于程序先用一个瓶子将try中的return的值装起来,后面不管finally如果修改a的值,返回值都不会变,但这只是因为返回的是基本数据类型,如果是引用类型,还是有点区别的,来看个栗子。

      先声明一个Stu类:

     1 public class Stu {
     2     String name;
     3 
     4     public String getName() {
     5         return name;
     6     }
     7 
     8     public void setName(String name) {
     9         this.name = name;
    10     }
    11 
    12 }

    测试一下:

     1 public class Test {
     2     public static void main(String[] args) {
     3         Stu stu = getReturn();
     4         System.out.println(stu.getName());
     5 
     6     }
     7 
     8     public static Stu getReturn(){
     9         Stu stu = new Stu();
    10         int d1 = 0;
    11         int d2 = 1;
    12         try {
    13             stu.setName("1");
    14             d1 = 1 / (d2);
    15             return stu;
    16         }catch (Exception e){
    17             stu.setName("2");
    18             System.out.println("Catch An Exception.");
    19         }finally {
    20             stu.setName("3");
    21             System.out.println("finally");
    22         }
    23         return stu;
    24     }
    25 }

    输出如下:

    1 finally
    2 3

    所以你看,现在还是变成了finally中的修改值,所以瓶子里装的只是变量中的内容,只能保证这个内容不会变,如果是引用变量,变量中存储的是引用对象的地址,finally中对引用对象的修改还是会影响到返回对象的。

      所以结论其实很简单,try,catch,finally语句块的return的优先级由低到高,先执行try中return之前的语句,如果遇到异常,则执行catch语句中return之前的代码,最后执行finally语句块,finally语句块中如果有return,那么程序就会提前返回,如果没有,则返回catch语句块中的return,如果没有遇到异常,则直接执行finally中的语句块,再看finally语句块中是否有return来决定返回结果。

      结论:
      1、不管是否出现异常,finally块中的代码都会执行;
      2、当try和catch中有return时,finally仍然会执行,finally中的return优先级大于catch大于try;
      3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
      4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

    备注:此文转载自 http://www.cnblogs.com/mfrank/p/7895660.html

  • 相关阅读:
    SpringBoot + SwaggerUI
    eclipse环境下:lombok安装及使用
    mysql列名名称包含特殊字符的处理
    java.lang.UnsupportedClassVersionError: com/mysql/cj/jdbc/Driver : Unsupported major.minor version 5
    PL/SQL连接远程服务器数据库,出现ORA-12154: TNS: 无法解析指定的连接标识符。
    tnsping无法ping通的问题,TNS-12535 TNS操作超时 (服务器环境:window server 2008R2 数据库环境:oracle 11 g)
    使用数据泵expdp、impdp备份和还原oracle数据库
    sql sever 2012重装数据库时,出现cannot find one or more components, Please reinstall the application.解决方法
    SQL Sever 2012版本数据库的完全安装流程
    SQL Sever 2012版本数据库的完全卸载
  • 原文地址:https://www.cnblogs.com/lu-manman/p/8083054.html
Copyright © 2011-2022 走看看