Java在try-catch-finally机制中的返回值

时间:2012-01-14 18:09:01

标签: java coding-style jvm

我刚刚遇到以下代码:

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. 我还没有找到在这种方式下使用并在实现中允许的finally机制中返回的用法 在JVM中。如果此代码构造用作返回的方法 错误代码,我认为有更好的方法来记录错误 或返回这些错误代码。有没有人找到这样的用途 构造
  3. 非常感谢提前。

    干杯, 韦恩

4 个答案:

答案 0 :(得分:13)

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

14.20.2节定义了

  

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

     
      
  1. 如果finally块正常完成,则try语句突然完成,原因是R。
  2.   
  3. 如果finally块因为S而突然完成,则try语句突然完成,原因为S(并且原因R被丢弃)。
  4.   

第14章的开头(section 14.1更精确)指明了正常和突然完成的内容。例如,具有给定值的return是一个突然完成。

因此,在这种情况下,finally块突然完成(原因:return具有给定值),因此try将因相同原因突然完成(并返回3) 。这在section 14.17 about the return statement以及

中得到了确认
  

如果表达式的评估正常完成,产生值V,则return语句突然完成,原因是返回值为V.

答案 1 :(得分:5)

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

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

IE中。它告诉我“最后块没有正常完成”。无论如何,我仍然得到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. 然后执行“finally”块,
  3. 新的返回值被压入堆栈
  4. 函数退出,并从堆栈中弹出返回值,从而忽略第一个。
  5. 确实非常简洁。

答案 2 :(得分:4)

实现取决于JVM,并且有许多JVM。你可以深入研究OpenJDK's source code以了解它如何实现finally,但这不是唯一的方法。就语言而言,重要的是行为。

我不明白第2点 - 为什么finally存在?它并不像你建议的那样只是一种返回错误代码的方法。你根本不必从finally内返回。该构造的存在是为了确保在某些代码段之后运行某种类型的清理代码,无论它是如何终止的,无论是正常的还是通过异常或返回。

答案 3 :(得分:0)

完全解释页面:439 => http://docs.oracle.com/javase/specs/jls/se8/jls8.pdf

如果表达式的评估正常完成,则生成一个 值V,然后return语句突然完成,原因是返回 值V。

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