我不懂这个。
在 lambda 表达式中,您根本无法引用非最终变量。
// doesn't compile
@Test
void methodReferenceTest() {
String message = "123";
message = "1234";
Supplier<Integer> messageLengthSupplier = () -> message.length();
System.out.print("Message length: ");
message = "12345";
System.out.print(messageLengthSupplier.get());
}
但是在方法引用中,您可以这样做,但是方法引用之后的任何重新分配都将被忽略。
@Test
void methodReferenceTest() {
String message = "123";
message = "1234";
Supplier<Integer> messageLengthSupplier = message::length;
System.out.print("Message length: ");
message = "12345";
System.out.print(messageLengthSupplier.get()); // prints 4
}
为什么 Java 创建者没有对 lambda 和方法引用使用一种方法?
有一些与 Java 创建者的设计决策相关的问题(示例),所以我相信这个问题与其他问题一样好(并且与主题一样)。
我不满意“因为方法引用就像方法句柄”(所以我不希望它被标记为问题的重复项)。那么,为什么它们的行为就像方法句柄一样?这只是重新表述问题而不是回答问题。
当你执行
message::length
时,你正在获取message
变量(这是一个字符串)的值,然后说“我想要这个字符串的
length
方法”。这就是为什么后续对 message
的赋值对方法没有影响 - 方法引用仍然引用原始字符串对象!
相比之下,当您使用 lambda 表达式时,至少在概念上,您捕获了
message
变量本身 - 在实际调用匿名函数之前不会检查其值。这可能会产生一些棘手的情况,例如,如果匿名函数的生存期超出了它创建的范围。有些语言(例如大多数 Lisp 方言和 Python)允许这样做。 Java 通过强制变量“有效地最终”来应对这一问题。另请参阅 维基百科上的“funarg 问题”。