尝试-捕获-最终机制中的 Java 返回值

2022-09-04 08:33:27

我刚刚遇到以下代码:

public class TestFinally {
    public static void main(String[] args) {
        int returnValue = function();

        System.out.println("Return value: " + returnValue);
    }

    public static int function() {
        try {
            return 1;
        } catch (Exception e){
            return 2;
        } finally{
            return 3;
        }
    }
}

毫无疑问,运行此代码将产生“返回值:3”的输出。

但是,我很好奇:

  1. JVM中内脏的机制。有谁知道 VM 是否通过覆盖第一个“返回 1”来替换堆栈上的返回值?如果是这样,在哪里可以找到有关此的更多信息。
  2. 我还没有在最终的机制中找到返回的用途,这种机制以这种方式使用,并允许在JVM中实现。如果将此代码构造用作返回错误代码的方法,则在我看来,有更好的方法来记录错误或返回这些错误代码。有没有人发现这种结构的用途?

提前非常感谢。

干杯,维恩


答案 1

我在Java语言规范中发现的至少定义了你的代码片段应该返回3。当然,它没有提到JVM应该如何实现这一点,以及可以做些什么可能的优化。

14.20.2 节定义了

如果由于任何其他原因R突然完成 try 块的执行,则执行最终块。然后有一个选择:

  1. 如果最终块正常完成,则 try 语句由于原因 R 而突然完成。
  2. 如果最终的块由于原因 S 而突然完成,则 try 语句由于原因 S 而突然完成(并且原因 R 被丢弃)。

第14章的开头(更确切地说是14.1节)指定了什么是正常和突然的完成。例如,具有给定值的 a 是突然完成。return

因此,在这种情况下,块突然完成(原因:具有给定值),因此将出于同样的原因突然完成(并返回3)。这在关于返回语句的第 14.17 节中也得到了证实finallyreturntry

如果表达式的计算正常完成,生成值 V,则 return 语句突然完成,原因是返回值为 V。


答案 2

FWIW,我收到有关功能的警告:

public static int function(){
    try{
        return 1;
    }catch(Exception e){
        return 2;
    }finally{
        return 3; //WARNING on this line
    }
}

即。它告诉我“终于块没有正常完成”。无论如何,我仍然得到3作为返回值。

无论如何,如果我尝试另一个例子:

public class TestFinally {
    public static void main(String[] args) {
        int returnValue = function();

        System.out.println("Return value: " + returnValue);
    }

    public static int function() {
        try {  

            return 1;  
            }  
        catch (Exception e) {   
            return 2;  
            }  
        finally {  
            System.out.println("i don't know if this will get printed out.");
        }
    }
}

输出将是(显然)

i don't know if this will get printed out.
Return value: 1

我不知道JVM是如何实现它的,但是最简单的方法来看待它(至少在概念上)是:

  1. “try”中的返回值被推送到堆栈上,
  2. 然后执行“最后”块,
  3. 新的返回值被推送到堆栈上
  4. 函数退出,并从堆栈中弹出返回值,从而忽略第一个函数。

确实是非常整洁的问题。