关于try-catch-finally块中的return语句
在Java的异常处理逻辑中,try-catch-finally的代码是按顺序执行,即如果try语句块中没有出现异常,那么将执行finally语句块;如果try语句块中出现异常,那么将执行对应的catch语句块的内容,然后继续执行finally语句块的内容。如果在try-catch-finally块中出现return语句会对返回结果产生怎样的影响呢?
Java在try-catch-finally块中对于函数返回值的处理逻辑是这样的:在执行finally语句之前会先将返回值的复制一份副本到一个本地变量表中,当finlly块中的逻辑执行完成以后,将副本读到操作栈顶,作为返回值返回使用。详见《深入Java虚拟机:JVM高级特性与最佳实践》第6章6.3.7节异常表运作的例子。
根据上述原因我们可以很容易得出下代码的输出值为1:
public static int inc() {
int x;
try {
x = 1;
return x;
} finally {
x = 3;
}
}
public static void main(String[] args) {
System.out.println("x = " + inc());
}
输出如下:
x = 1
但是,如果finally有return语句结果又会如何呢
public static int inc() {
int x;
try {
x = 1;
return x;
} finally {
x = 3;
return x;
}
}
public static void main(String[] args) {
System.out.println("x = " + inc());
}
输出如下:
x = 3
这是由于在finally块中有return语句,java虚拟机将先执行finally块中的return语句返回之后就不会再执行try中的return,从而将try块中的return覆盖了。这种写法,编译是可以编译通过的,但是编译器会给予警告,所以不推荐在finally中写return,这会破坏程序的完整性。
那么,不在finally块中进行return就一定没问题吗?
事实上,如果在finally块中操作的对象不是值类型而是引用类型,那么对于引用类型的对象的属性进行修改则会产生影响,代码如下:
public static IntContainer inc() {
IntContainer x = new IntContainer();
try {
return x;
} finally {
x.val++;
}
}
public static class IntContainer {
int val = 1;
}
public static void main(String[] args) {
System.out.println("x.val = " + inc().val);
}
输出如下:
x.val = 2
这是由于方法返回的是对象的引用,对于引用本身finally块虽然没有进行修改,但是对于引用对象属性的修改还是会生效。
总结
1、finally中的代码总会被执行。
2、当try、catch中有return时,也会执行finally。return的时候,要注意返回值的类型,是否受到finally中代码的影响。
3、finally中有return时,会直接在finally中退出,导致try、catch中的return失效。