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

时间:2012-08-15 21:29:11

标签: java return return-value finally

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

6 个答案:

答案 0 :(得分:16)

  

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

是的,但在第二次通话之前确定了返回值。

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

来自section 14.17 of the JLS

  

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

根据section 14.20.2 of the JLS执行然后转移到finally块。但是,这并没有在return语句中重新计算表达式。

如果您的最终阻止是:

finally { return increment(); }

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

答案 1 :(得分:5)

请参阅my comment

如果你有2,它会返回finally { return increment(); }。 在finally块之前计算第一个return语句的表达式。请参阅Section §14.20.2 of the JLS

  

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

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

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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

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