为什么等效的 lambda 表达式和方法引用在捕获静态字段值时表现不同?
Why do equivalent lambda expression and method reference behave differently when capturing static field value?
我对 Java lambda 和方法引用行为有点困惑。例如,我们有这个代码:
import java.util.function.Consumer;
public class Main {
private static StringBuilder sBuilder = new StringBuilder("1");
public static void main(String[] args) {
Consumer<String> consumer = s -> sBuilder.append(s);
sBuilder = new StringBuilder("2");
consumer.accept("3");
System.out.println(sBuilder);
}
}
输出:
23
这按预期工作,但如果我们替换
s -> sBuilder.append(s)
和
sBuilder::append
输出将是:
2
你知道如何解释这个吗?这不是一样的东西吗?谢谢
在 lambda 表达式中,sBuilder
字段被捕获,但未被计算。它只会在相应的函数接口方法被调用时被评估。那时,sBuilder
引用创建并分配给字段的新实例
sBuilder = new StringBuilder("2");
在方法引用中,立即计算 sBuilder
字段以生成 Consumer
实例。该值引用在静态初始化程序中创建的实例
private static StringBuilder sBuilder = new StringBuilder("1");
并且 Consumer
将对那个进行操作。你打印新的。
来自 Java 语言规范,关于 Run-Time Evaluation of Method References
The body of an invocation method depends on the form of the method
reference expression, as follows:
If the form is ExpressionName :: [TypeArguments] Identifier
or
Primary :: [TypeArguments] Identifier
, then the body of the
invocation method has the effect of a method invocation expression for
a compile-time declaration which is the compile-time declaration of
the method reference expression. Run-time evaluation of the method
invocation expression is as specified in §15.12.4.3, §15.12.4.4, and
§15.12.4.5, where:
The invocation mode is derived from the compile-time declaration as specified in §15.12.3.
The target reference is the value of ExpressionName
or Primary
, as determined when the method reference expression was
evaluated.
The arguments to the method invocation expression are the formal parameters of the invocation method.
我对 Java lambda 和方法引用行为有点困惑。例如,我们有这个代码:
import java.util.function.Consumer;
public class Main {
private static StringBuilder sBuilder = new StringBuilder("1");
public static void main(String[] args) {
Consumer<String> consumer = s -> sBuilder.append(s);
sBuilder = new StringBuilder("2");
consumer.accept("3");
System.out.println(sBuilder);
}
}
输出:
23
这按预期工作,但如果我们替换
s -> sBuilder.append(s)
和
sBuilder::append
输出将是:
2
你知道如何解释这个吗?这不是一样的东西吗?谢谢
在 lambda 表达式中,sBuilder
字段被捕获,但未被计算。它只会在相应的函数接口方法被调用时被评估。那时,sBuilder
引用创建并分配给字段的新实例
sBuilder = new StringBuilder("2");
在方法引用中,立即计算 sBuilder
字段以生成 Consumer
实例。该值引用在静态初始化程序中创建的实例
private static StringBuilder sBuilder = new StringBuilder("1");
并且 Consumer
将对那个进行操作。你打印新的。
来自 Java 语言规范,关于 Run-Time Evaluation of Method References
The body of an invocation method depends on the form of the method reference expression, as follows:
If the form is
ExpressionName :: [TypeArguments] Identifier
orPrimary :: [TypeArguments] Identifier
, then the body of the invocation method has the effect of a method invocation expression for a compile-time declaration which is the compile-time declaration of the method reference expression. Run-time evaluation of the method invocation expression is as specified in §15.12.4.3, §15.12.4.4, and §15.12.4.5, where:
The invocation mode is derived from the compile-time declaration as specified in §15.12.3.
The target reference is the value of
ExpressionName
orPrimary
, as determined when the method reference expression was evaluated.The arguments to the method invocation expression are the formal parameters of the invocation method.