从finally块返回时Java的奇怪行为

试试这段代码。 为什么getValueB()返回1而不是2? 毕竟,increment()函数被调用两次。

public class ReturningFromFinally { public static int getValueA() // This returns 2 as expected { try { return 1; } finally { return 2; } } public static int getValueB() // I expect this to return 2, but it returns 1 { try { return increment(); } finally { increment(); } } static int counter = 0; static int increment() { counter ++; return counter; } public static void main(String[] args) { System.out.println(getValueA()); // prints 2 as expected System.out.println(getValueB()); // why does it print 1? } } 

毕竟,increment()函数被调用两次。

是的,但返回值是第二次调用之前确定的。

返回的值由在该时间点返回语句中的表达式的求值来确定 – 而不是“就在执行离开方法之前”。

从JLS第14.17节 :

带有Expression的return语句尝试将控制权转移给包含它的方法的调用者; Expression的值成为方法调用的值。 更准确地说, 执行这样的return语句首先评估Expression 。 如果表达式的评估由于某种原因突然完成,则返回语句因此而突然完成。 如果表达式的评估正常完成,产生值V,则return语句突然完成,原因是返回值为V.

然后 根据JLS的14.20.2部分将执行转移到finally块。 但是,这并不会在return语句中重新计算表达式。

如果你的finally块是:

 finally { return increment(); } 

然后,新的返回值将是该方法的最终结果(根据第14.20.2节) – 但你没有这样做。

看我的评论 。

如果你finally { return increment(); }它将返回2 finally { return increment(); } finally { return increment(); } 。 在finally块之前计算第一个return语句的表达式。 参见JLS的第14.20.2节 。

如果try块的执行正常完成,则执行finally块,然后有一个选择:

  • 如果finally块正常完成,则try语句正常完成。
  • 如果finally块因为原因S突然完成,则try语句因为S突然完成。

现在调用getValue2 (就像你现在一样)两次将导致1后跟3

GetValue2方法中的finally块不返回任何内容。 它只调用增加counter的方法。

因为在你的getValue2()方法中,你最后只是调用increment(),它不会返回它。 所以你的代码正在做的是它递增并返回counter(1),然后将counter递增到2,但不返回它。

在第二个示例中没有显式返回。 在这种情况下,它将返回try块中的值。 它具有直观意义,因为Java已经在try块中执行了代码。 在执行finally块之后,不会再执行该块。

finally方法的目的是确保在任何情况下都关闭资源。 考虑这个例子:

 public List getPersons() { Connection conn = openConnection(); try { return selectPersons(conn); } finally { conn.close() } } 

执行selectPersons(conn)后执行conn.close()语句。 否则selectPersons(conn)会引发连接关闭错误。