当finally遇上return
刚学异常捕获机制时,会有这么一个问题,当try中出现return语句时,那么finally语句还会不会执行呢?
先从一道代码题入手,那么该段代码的输出是什么呢?
public static int testFinally1() {
int i = 0;
try {
++i;
return i;
} catch (Exception e) {
++i;
return i;
} finally {
System.out.println("finally");
}
}
输出结果截图
可以看得出,try语句块中即使有了return语句,finally也照样执行了,但从执行的结果来看,finally先执行,然后再执行return 0的语句。
由此道题总结出一下两点:
(1)在java的异常捕获机制中,finally的语句块保证了不管遇到什么情况,finally语句块一定被执行,除非突然出现崩溃或者是System.exit(),这两种情况不谈,太特殊了。
(2)当程序执行到return语句中,就意味着结束对当前函数的调用并跳出这个函数体,任何语句要执行都只能在return前执行,因此finally语句块中代码也是在return前执行的。
从深层理解来看,当执行到try中的return语句时,return关键词会先把i放入到一个临时的栈空间中,然后再去执行finally中的语句,执行完毕后,再把临时栈空间中的值返回。
如果在finally中修改i的值呢?
public static int testFinally1() {
int i = 0;
try {
++i;
return i;
} catch (Exception e) {
++i;
return i;
} finally {
++i;
System.out.println("finally");
}
}
按理说,应该返回2啊,可事实的返回结果为:
刚才解释过,只有return才会把i的值放入到临时的栈空间中,执行try中return i时,return将i的值,也就是1放入到栈空间中,finally执行时,i的值确实等于2,但是没有更新到临时的栈空间中,finally执行完后,返回栈空间中的值,也就是1.
如果在finally语句块中return i呢?
public static int testFinally1() {
int i = 0;
try {
++i;
return i;
} catch (Exception e) {
++i;
return i;
} finally {
++i;
System.out.println("finally");
return i;
}
}
返回结果:
这是由于执行到finally中的return时,导致栈空间中的值被及时更新了,导致返回的结果是2。
但是这仅仅局限于基本数据类型,简单的理解为对于基本数据类型的变量,finally语句中的return会覆盖try中的return。
那么对于引用类型呢?注意我没在finally中返回。
public static StringBuilder testFinally2() {
StringBuilder sb = new StringBuilder();
try {
sb.append("a");
return sb;
} catch (Exception e) {
sb.append("b");
return sb;
} finally {
System.out.println("finally");
sb.append("c");
}
}
输出结果:
从这里可以分析出,try中的return把sb这个变量引用而不是把“a"存入临时的栈空间中了,那么在finally中即使没有更新栈空间的情况下,返回的值也是最新的值,即“ac”。
那么,可以总结一下,对于基本数据类型的变量,临时栈空间中直接存的就是具体的一个值。而对于引用变量,栈空间存放的是这个引用变量,而非具体的一个值。