33

return;当try 块中存在时,我对 try-finally 执行感到困惑。在我的理解中,finally 块总是会被执行,即在返回调用方法之前。在考虑以下简单代码时:

public class TryCatchTest {
    public static void main(String[] args){
        System.out.println(test());
    }
    static int test(){
        int x = 1;
        try{
            return x;
        }
        finally{
            x = x + 1;
        }
    }
}

打印出来的结果其实是1。这是否意味着finally块没有被执行?有人可以帮我吗?

4

3 回答 3

29

当您从try块返回时,返回值存储在该方法的堆栈帧中。之后执行 finally 块。

更改 finally 块中的值不会更改堆栈中已经存在的值。但是,如果从 finally 块再次返回,堆栈上的返回值将被覆盖,并x返回新的。

如果你打印xfinally 块中的值,你就会知道它被执行了,并且x会打印出 的值。

static int test(){
    int x = 1;
    try{
        return x;
    }
    finally{
        x = x + 1;
        System.out.println(x);  // Prints new value of x
    }
}

注意:在返回引用值的情况下,引用的值存储在堆栈中。在这种情况下,您可以使用该引用更改对象的值。

StringBuilder builder = new StringBuilder("");
try {
    builder.append("Rohit ");
    return builder;

} finally {
    // Here you are changing the object pointed to by the reference
    builder.append("Jain");  // Return value will be `Rohit Jain`

    // However this will not nullify the return value. 
    // The value returned will still be `Rohit Jain`
    builder =  null;
}

推荐阅读:

于 2013-08-08T16:41:23.173 回答
12

finally 块被执行。局部变量递增。但是该局部变量的值已经被复制为返回值。

来自 Java 语言规范,14.17:返回语句

带有 Expression 的 return 语句试图将控制权转移给包含它的方法的调用者;表达式的值成为方法调用的值。

...

前面的描述说“尝试转移控制”,而不仅仅是“转移控制”,因为如果方法或构造函数中有任何 try 语句(第 14.20 节),其 try 块或 catch 子句包含 return 语句,那么这些的任何 finally 子句在将控制权转移到方法或构造函数的调用者之前,将按从内到外的顺序执行 try 语句。finally 子句的突然完成可能会中断由 return 语句启动的控制转移

于 2013-08-08T16:41:39.177 回答
0

您在退出尝试之前返回 x。我会这样做:

public class TryCatchTest {
    public static void main(String[] args) {
        System.out.println(test());
    }
    static int test() {
        int x = 1;
        try {
            do something with x.
        } finally {
            do something that will happen even in case of error;
            x = x + 1;
            return x;
        }
    }
}
于 2013-08-08T17:12:53.577 回答