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

Posted

技术标签:

【中文标题】从 finally 块返回时 Java 的奇怪行为【英文标题】:Java's strange behavior while returning from finally block 【发布时间】:2012-08-12 05:45:00 【问题描述】:

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

【问题讨论】:

如果你有finally return increment(); ,它将返回2。第一个return 语句的表达式在finally 块之前计算。见Section §14.20.2 of the JLS。 或者如果他有 ++counter,它会在第二种方法中返回 2 getValue2 也许最好调用不同的 incrementxxx() 函数(一个在return,另一个在finally),以不同的量递增,只是为了更好地了解问题 @ant 不,它不会。 counter++;++counter; 是表达式语句,效果相同。 是的,事实并非如此。在这种情况下,它们具有相同的效果,但并非总是如此 ***.com/a/24858/169277 【参考方案1】:

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

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

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

来自section 14.17 of the JLS:

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

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

如果你的 finally 块是:

finally  return increment(); 

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

【讨论】:

附带说明,您不应该在 finally 块中返回任何内容或抛出任何异常。如果这样做,它会掩盖先前发出的返回值(在 try 内),或作为 try/catch 逻辑的一部分抛出的任何异常。【参考方案2】:

见my comment。

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

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

如果finally 块正常完成,则try 语句正常完成。 如果finally 块由于原因S 而突然完成,那么try 语句由于原因S 而突然完成。

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

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

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

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

【讨论】:

以上是关于从 finally 块返回时 Java 的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

从 Java 中的 finally 块返回

Java中,finally在try语句块中的return前执行还是后执行

Java中,finally在try语句块中的return前执行还是后执行

java finally 与return

从Java访问元组的奇怪行为

java基础题