博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Java疑难杂症】有return的情况下try catch finally的执行顺序
阅读量:6155 次
发布时间:2019-06-21

本文共 4853 字,大约阅读时间需要 16 分钟。

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

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,会先返回谁呢?我们来进行一下测试:

public class Test {    public static void main(String[] args) {        int i = Test.getReturn();        System.out.println(i);    }    public static int getReturn(){        int a = 0;        int d1 = 0;        int d2 = 1;        try {
      //try语句块中没有发生异常 a = 10; d1 = 1 / d2; return a; }catch (Exception e){ a = 20; System.out.println("Catch An Exception."); return a; }finally { a = 30; System.out.println("finally"); return a; } }}

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

finally30

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

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

public class Test {    public static void main(String[] args) {        int i = getReturn();        System.out.println(i);    }    public static int getReturn(){        int a = 0;        int d1 = 0;        int d2 = 1;        try {            a = 10;            d1 = 1 / (--d2);            return a;        }catch (Exception e){            a = 20;            System.out.println("Catch An Exception.");            return a;        }finally {            a = 30;            System.out.println("finally");            return a;        }    }}

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

Catch An Exception.finally30

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

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

public class Test {    public static void main(String[] args) {        int i = getReturn();        System.out.println(i);    }    public static int getReturn(){        int a = 0;        int d1 = 0;        int d2 = 1;        try {            a = 10;            d1 = 1 / (--d2);            return a;        }catch (Exception e){            a = 20;            System.out.println("Catch An Exception.");            return a;        }finally {            a = 30;            System.out.println("finally");            //return a;        }    }}

  输出如下:

Catch An Exception.finally20

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

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

public class Test {    public static void main(String[] args) {        int i = getReturn();        System.out.println(i);    }    public static int getReturn(){        int a = 0;        int d1 = 0;        int d2 = 1;        try {            a = 10;            d1 = 1 / (d2);            return a;        }catch (Exception e){            a = 20;            System.out.println("Catch An Exception.");            //return a;        }finally {            a = 30;            System.out.println("finally");            //return a;        }        return a;    }}

  输出如下:

finally10

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

  先声明一个Stu类:

public class Stu {    String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

  测试一下:

public class Test {    public static void main(String[] args) {        Stu stu = getReturn();        System.out.println(stu.getName());    }    public static Stu getReturn(){        Stu stu = new Stu();        int d1 = 0;        int d2 = 1;        try {            stu.setName("1");            d1 = 1 / (d2);            return stu;        }catch (Exception e){            stu.setName("2");            System.out.println("Catch An Exception.");        }finally {            stu.setName("3");            System.out.println("finally");        }        return stu;    }}

  输出如下:

finally3

  所以你看,现在还是变成了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://tgbfa.baihongyu.com/

你可能感兴趣的文章
Java 8 中的 Streams API 详解
查看>>
react-navigation
查看>>
为什么要学习?
查看>>
oracle查询A表中主键都被哪些表引用了?
查看>>
最近开发用的各种环境配置以及文件
查看>>
Plus One Linked List
查看>>
BZOJ 2300 防线修建
查看>>
传球游戏(dp)
查看>>
小P的太空旅行
查看>>
Android数据库SQLite性能优化技巧
查看>>
大话cocos2d-js(3)
查看>>
关于98/ME和2000/XP双系统的安装和启动原理的讨论
查看>>
注册时的一些验证
查看>>
Windows Phone 项目实战之账户助手升级
查看>>
4.01、Linux异常
查看>>
***使用PHP实现文件上传和多文件上传
查看>>
mongodb的更新操作符
查看>>
FusionCube 9000 虚拟化之数据库场景(虚拟化超融合基础设施)
查看>>
Linux进程调度与源码分析(五)——schedule代码流程
查看>>
截获WndProc过程
查看>>