实例方法参考和Lambda参数

问题描述 投票:0回答:2

我无法理解方法引用的语法,其中有两个参数

a
b
,引用是
a
b
上的方法。

例如我明白如何

Arrays.sort(personArray, comparators::compareByName);

相当于

Arrays.sort(personArray, (o1, o2) -> comparators.compareByName(o1, o2));

因为在那种情况下,lambda 参数与方法调用参数匹配

(o1, o2)
.

但是对于这个 lambda

stream.sorted((o1, o2) -> o1.compareToIgnoreCase(o2));

我的 IDE 告诉我这等同于:

stream.sorted(String::compareToIgnoreCase);

我没有找到替换该语法的规则:

a.method(b)
与方法参考。

例如,如果 lambda 有三个或更多参数怎么办?那是合法的吗?第一个参数是否成为方法目标,其余成为参数?

java lambda java-8 closures method-reference
2个回答
8
投票

我认为您正在寻找 JLS 部分 15.13.3,其中包括:

如果形式为

ReferenceType :: [TypeArguments] Identifier
,则调用方法体同样具有编译时声明的方法调用表达式的作用,即方法引用表达式的编译时声明。方法调用表达式的运行时评估如 §15.12.4.3、§15.12.4.4 和 §15.12.4.5 中所述,其中:

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

  • 如果编译时声明的是实例方法,那么目标引用就是调用方法的第一个形参。否则,没有目标参考。

  • 如果编译时声明是实例方法,则方法调用表达式的参数(如果有的话)是调用方法的第二个和后续形式参数。否则,方法调用表达式的参数是调用方法的形式参数。

基本上请注意最后两个项目符号。

例如,如果 lambda 有三个或更多参数怎么办?那是合法的吗?第一个参数是否成为方法目标,其余成为参数?

是的:)


1
投票

我会在这里举几个例子,供那些觉得 Oracle 文档有点难以理解的人使用。 假设您需要一个 Comparator 实例的引用:

.sorted(String::compareTo)

String::compareTo 等同于:

(String a, String b) -> a.compareTo(b);

因为,正如 Jon 解释的那样,方法引用将被转换为需要 2 个参数的 lambda。在流中传递的实际任意对象作为第一个参数,还有一个参数(因为 Comparator 需要

int compare(T o1, T o2)
)。 另一种情况:

.map(Employee::getSalary)

在这种情况下,地图需要:功能。函数需要实现

R apply(T var1)
- 一个有 1 个参数的方法。在这种情况下,将传递给 lambda 的唯一参数是实际的任意对象 - Employee 上的实例。

总而言之——根据编译时上下文,对任意对象的方法引用将始终“转换”为一个 lambda,该 lambda 期望该对象作为第一个参数 + 目标方法所需的任意数量的参数以相同的对应顺序。

© www.soinside.com 2019 - 2024. All rights reserved.