11

试试这段代码。为什么 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?
      }
}
4

6 回答 6

18

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

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

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

JLS 的第 14.17 节

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

然后根据 JLS 的第 14.20.2 节将执行转移到finally块中。不过,这不会重新评估 return 语句中的表达式。

如果您的 finally 块是:

finally { return increment(); }

那么这个新的返回值将是该方法的最终结果(根据第 14.20.2 节) - 但你没有这样做。

于 2012-08-15T21:33:41.993 回答
5

我的评论

2如果你有它会返回finally { return increment(); }。第一条return语句的表达式在 finally 块之前进行评估。请参阅JLS 的第 14.20.2 节

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

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

调用getValue2(正如你现在所拥有的那样)两次将导致1后面跟着3.

于 2012-08-15T21:35:04.293 回答
0

方法中的finallyGetValue2不返回任何内容。它只是调用方法来增加counter

于 2012-08-15T21:33:46.277 回答
0

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

于 2012-08-15T21:34:22.360 回答
0

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

于 2012-08-27T05:06:07.247 回答
0

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

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

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

于 2014-07-09T15:25:27.127 回答