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

我刚刚遇到以下代码:

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中实现。 如果此代码构造用作返回错误代码的方法,则在我看来有更好的方法来记录错误或返回这些错误代码。 有没有人发现这种结构的用途?

提前谢谢了。

干杯,Vern

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

第14.20.2节定义了这一点

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

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

第14章的开头(更准确的是第14.1节 )规定了正常和突然完成的内容。 例如,具有给定值的return是突然完成。

因此,在这种情况下, finally块突然完成(原因: return给定值),因此try将突然完成同样的原因(并返回3)。 关于退货声明 , 第14.17节也证实了这一点

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

实现取决于JVM,并且有许多JVM。 您可以深入了解OpenJDK的源代码以了解它finally如何实现,但这不是唯一的方法。 就语言而言,重要的是行为。

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

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

 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. 函数退出,并从堆栈中弹出返回值,从而忽略第一个。

确实很整洁的问题。

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

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

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