关于Java finally的面试题(finally的执行时机,finally和return的先后顺序)
考点:finally语句必然执行 和 return返回值的情况
面试官问题:
1.try-catch-finally 中哪个部分可以省略?
答: catch和finally可以省略其中一个 , catch和finally不能同时省略
注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也不会这样去写代码。
2.什么时候用到finally呢?finally语句在try或catch中的return语句执行之后,还是return返回之前执行呢?
在try{…}catch{…}捕获异常处理语句中:
finally{}必然执行的异常的统一出口,无论是否发生异常,finally必然执行;
除非电脑没电、关机、软件关闭、程序从内存中消失、finally之前出现exit退出,否则finally必然执行。
问题:try-catch-finally 中,如果 catch 中有 return 了,finally 还会执行吗?
答:finally中的代码会执行
详解:执行流程:
- 1.先计算返回值, 并将返回值存储起来, 等待返回;
- 2.执行finally代码块;
- 3.将之前存储的返回值, 返回出去。
需注意:
- 返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值(非引用数据类型)做任何的改变,返回的值都不会改变
- finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值不是try或 catch中的值
- 如果在try或catch中停止了JVM,则finally不会执行.例如停电…, 或通过如下代码退出 JVM:System.exit(0);
那么执行顺序用代码来解释
看下面这部分代码:
finally举例1:(即使return,在准备返回值与跳出函数之间,仍会执行finally中的语句)
代码:
运行结果:
finally举例2:(引用数据类型和非引用数据类型的区别)
代码:(引用数据类型)
运行结果:
从结果可看出:由于 返回值是引用数据类型
,在return之前准备好p(将引用地址进行备份),但是finally中通过引用数据类型的地址,修改了具体的值,所以还是显示的最终结果会更改属性值为28;内存分析:
代码:(非引用数据类型) 及 运行结果:
内存分析:
为什么会产生上面这种原因,就是下面要说的关于非引用数据类型(基本数据类型)和引用数据类型的区别:
- 基本数据类型存在于栈里,那么 return备份的就是数据 。而finally改变的是栈里的数据,但是不会改变备份数据,所以返回值不变。
- 引用数据类型,数据存在于堆中开辟的空间里,而栈中存储的是堆所对应的空间地址,因此 return备份的是栈中的空间地址 ,但是finally改变的是堆中的数据,所以当return返回地址时,查找到堆中的数据就是被改变了。
那么看完了上面,下面要说的就是fially{…}不执行的条件
finally举例3 :exit()退出[表明终止后面的代码],不执行finally
这部分代码因为除数不能为0,所以会抛出异常,进入到catch{}里面,在catch里面有一行代码 System.exit(0); 这一行代码的意思就是强制退出程序,因此finally不会执行
- 退出代码:System.exit( 0)可以输入0.1.2.3 0表示正常退出 剩下是非正常退出。
总结:
- finally{…}必然执行异常的统一出口,无论是否发生异常,finally必然执行
- 除非电脑没电、关机、软件关闭、程序从内存中消失、finally之前出现exit退出,否则finally必然执行。
- 如果是基本数据类型先return 后finally 不会改变值 因为return备份的是值。
- 如果是引用数据类型 先return 后finally 会改变值, 因为return备份的是引用类型在堆中的地址,而finally改变的是堆中的值。