从 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在try语句块中的return前执行还是后执行