为什么在捕获静态字段值时,等效的lambda表达式和方法引用的行为会有所不同?

我对Java lambdas和方法引用行为有点困惑。 例如,我们有这个代码:

import java.util.function.Consumer; public class Main { private static StringBuilder sBuilder = new StringBuilder("1"); public static void main(String[] args) { Consumer consumer = s -> sBuilder.append(s); sBuilder = new StringBuilder("2"); consumer.accept("3"); System.out.println(sBuilder); } } 

输出:

 23 

这可以按预期工作,但如果我们更换

s – > sBuilder.append(s)

sBuilder ::追加

输出将是:

 2 

你有什么想法解释这个吗? 这不是一回事吗? 谢谢。

在lambda表达式中,捕获sBuilder字段,但不进行求值。 只有在调用相应的函数接口方法时才会对其进行求值。 此时, sBuilder引用创建并分配给该字段的新实例

 sBuilder = new StringBuilder("2"); 

在方法引用中,立即计算sBuilder字段以生成Consumer实例。 该值引用在静态初始化程序中创建的实例

 private static StringBuilder sBuilder = new StringBuilder("1"); 

Consumer将在那个上运作。 你打印新的。


来自Java语言规范,关于方法参考的运行时评估

调用方法的主体取决于方法引用表达式的forms,如下所示:

如果表单是ExpressionName :: [TypeArguments] IdentifierPrimary :: [TypeArguments] Identifier ,则调用方法的主体具有编译时声明的方法调用表达式的效果,该声明是编译时声明的方法参考表达式。 方法调用表达式的运行时评估如§15.12.4.3,§15.12.4.4和§15.12.4.5中所规定,其中:

  • 调用模式源自§15.12.3中指定的编译时声明。

  • 目标引用是ExpressionNamePrimary的值,在评估方法引用表达式时确定。

  • 方法调用表达式的参数是调用方法的forms参数。