在java编程中捕获异常,会经常使用finally语句块,也是突然碰到了几个有意思的例子,正好对finally语句块做下简单的回顾。
我们知道,在代码执行层面,即使try里包含continue,break,return这些断点块,try块结束后,finally块也会执行。finally一般是做一些善后清理工作,所以可以将回收代码放入finally语句块中。而java的垃圾回收机制其实不会回收任何物理资源,在java程序中,通常使用finally来回收物理资源,如果文件流、连接池、新实例等等,finally块的作用就是为了保证无论出现什么情况,finally块里的代码一定会被执行。
今天要讲的有意思的例子就是return块与finally块的关系。
第一个问题:try{}里有一个return语句,那么紧跟在这个try{}后面的finally{}中的代码是否会被执行?如果会的话,什么时候被执行,在return之前还是return之后?看几个例子,返回值应该分别是什么。
private int test1() {
try {
return 1;
} finally {
return 3;
}
}
private int test2() {
int b = 1;
try {
b += 1;
} finally {
b += 2;
}
return b += 3;
}
private int test3() {
int b = 1;
try {
return b += 1;
} finally {
b += 2;
}
return b += 3;
}
private int test4() {
int b = 1;
try {
return b += 1;
} finally {
return b += 2;
}
}
由于程序执行return就意味着结束对当前函数的调用并跳出这个函数体,因此任何语句要执行都只能在return前执行(除非碰到exit函数),因此finally块里的代码也是在return之前执行的。如果try-finally或者catch-finally中都有return,那么finally块中的return将会覆盖别处的return语句,最终返回到调用者那里的是finally中return的值。所以:
test1中,finally块的return会覆盖try块的return,返回3;
test2中,try-finally块都没有return,会全部执行,最终函数返回7;
test3中,finally块并没有return,所以b+=2只是局部变化,结果并不会返回给try块中的return,并且try块中return后不再执行函数最终的return,返回2;
test4中,与test3的区别是finally块有return,所以b=2的基础上会再+2,最终函数返回4。
第二个问题,finally块是不是一定会被执行?
其实并不一定,两种情况不会:
1.try块未执行就异常或退出,finally不会执行;
2.try块中强制退出(System.exit(0);)。