finally和return的执行顺序

部分demo代码来自https://blog.csdn.net/jdfk423/article/details/80406297#commentsedit

私以为原文结论不太准确,也不太完善,以下是个人见解。

问题1:try和catch中有return时,finally里面的语句会被执行吗

(1) 执行try中的return时

public class TryDemo {
    public static int show() {
        try {
            return 1;  
        }finally{
            System.out.println("finally模块被执行");
        }
    }
    public static void main(String args[]) {
        System.out.println(show());
    }
}

输出结果如下:

这里写图片描述

(2) 执行catch中的return时

public class TryDemo {
    public static int show() {
        try {
            int a = 8/0;
            return 1;  // 这里因为异常发生,此行代码不会被执行
        }catch (Exception e) {
            // 从结果上看,这行代码被执行了,那么是它先执行,还是finally先执行呢?结论看问题2
            return 2; 
        }finally{
            System.out.println("finally模块被执行");
        }
    }
    public static void main(String args[]) {
        System.out.println(show());
    }
}

其结果如下:

这里写图片描述

我们可以得出结论:

结论1:如果程序是从try代码块或者catch代码块中返回时,finally中的代码总会执行。

引申:finally代码什么时候不会被执行?

答案:

1.如果try语句或者catch语句里存在强制退出语句System.exit(0),代表虚拟机被终止。

2.在执行try...catch语句前已经有了return语句返回,后面的程序不再被执行。


问题2:try代码块或者catch代码块中的return语句  和 finally中的代码谁先被执行?

demo1 返回值是基本数据类型

public class TryDemo {
    public static int show() {
        int result = 0;
        try {
            return result;
        }finally{
            System.out.println("finally模块被执行");
            result = 1;
        }
    }
    public static void main(String args[]) {
        System.out.println(show());
    }
}

demo2 返回值是引用数据类型

public class TryDemo {
    public static Object show() {
        Object obj = new Object();
        try {
            return obj;
        }finally{
            System.out.println("finally模块被执行");
            obj = null;
        }
    }
    public static void main(String args[]) {
        System.out.println(show());
    }
}


结果分别如下

这里写图片描述这里写图片描述

我们可以得出结论:

结论2:try代码块或者catch代码块中的return语句 优先于finally中的代码块执行,且函数真正返回之前,finally中的代码块执行必须先执行,所以可以这样说,finally语句在return语句执行之后return返回之前执行的。

到这里还没有结束,需要注意虽然finally中的语句(非return语句)不会影响最终返回值,但它对返回值的修改其实是生效了的,demo1中因为是基本数据类型,所以看不出来,demo2中返回值是new Object这个对象的地址引用,它并没有被修改,修改的只是obj这个局部变量的指向,原先的对象本身并没有发生改变,所以说demo2其实不太ok。

这里我先贴出一个结论,结论来自于下文中我推荐的博客:

总结:对于finally块中没有return语句的情况,方法在返回之前会先将返回值保存在局部变量表中的某个slot中,然后执行finally块中的语句,之后再将保存在局部变量表中某个slot中的数据放入操作数栈的栈顶并进行返回,因此对于基本数据类型而言,若在finally块中改变其值,并不会影响最后return的值,而若是引用数据类型,改变对象的内容信息是会作用到最后的返回值上的(因为返回值实际并不是对象本身,而是其引用)。
而对于finally块中包含了return语句的情况,则在try块中的return执行之后返回之前,会先goto到finally块中,而在goto之前并不会对try块中要返回的值进行保护,而是直接去执行finally块中的语句,并最终执行finally块中的return语句并直接返回,而忽略try块中的return语句的返回,因此最终返回的值是在finally块中改变之后的值。

demo3

public class TryDemo {

	public static People show() {
		People p = new People(18);
		try {
			return p;
		} finally {
			System.out.println("finally模块被执行");
			p.setAge(20);
		}
	}

	public static void main(String args[]) {
		System.out.println(show().getAge());
	}
}

class People {
	private int age;
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public People(int age) {
		super();
		this.age = age;
	}

}

结果如图:


问题3:如果finally中也有return的时候,finally块中包含的return语句对返回值会有怎样的影响

public class TryDemo {
    public static int show() {
        try {
            int a = 8/0;
            return 1;
        }catch (Exception e) {
            return 2;
        }finally{
            System.out.println("finally模块被执行");
            return 0;
        }
    }
    public static void main(String args[]) {
        System.out.println(show());
    }
}

执行结果如下:

这里写图片描述

结论:我们可以看到当finally有返回值时,会选择返回finally语句中的返回值,不会再去返回try或者catch中的返回值。另外我通过debug发现,try或者catch语句中的return语句还是有被执行的,但是在最终选择返回值时,选择了执行finally语句中的。

对于问题2和问题3的进一步深入学习了解,对于以上几个demo更好的解释我推荐这篇博文,从字节码指令层次分析https://blog.csdn.net/abinge317/article/details/52253768

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值