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

Cod*_*lue 10 java return finally return-value

试试这段代码.为什么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?
      }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 17

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

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

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

JLS第14.17节:

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

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

如果你的finally块是:

finally { return increment(); }
Run Code Online (Sandbox Code Playgroud)

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

  • 附带说明,您不应返回任何东西或将任何异常抛出到finally块之外。如果这样做,它将掩盖先前发出的返回值(在try内),或作为try / catch逻辑的一部分抛出的任何异常。 (2认同)

old*_*inb 5

我的评论.

2如果你有,它会回来finally { return increment(); }.return在finally块之前评估第一个语句的表达式.参见JLS的第14.20.2节.

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

  • 如果finally块正常完成,则try语句正常完成.
  • 如果finally块因为某些原因而突然完成S,则该try语句会因为原因而突然完成S.

getValue2现在调用(如你所知)两次将导致1后跟3.