为什么在捕获静态字段值时,等效的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] Identifier
或Primary :: [TypeArguments] Identifier
,则调用方法的主体具有编译时声明的方法调用表达式的效果,该声明是编译时声明的方法参考表达式。 方法调用表达式的运行时评估如§15.12.4.3,§15.12.4.4和§15.12.4.5中所规定,其中:
调用模式源自§15.12.3中指定的编译时声明。
目标引用是
ExpressionName
或Primary
的值,在评估方法引用表达式时确定。方法调用表达式的参数是调用方法的forms参数。