我无法理解方法引用的语法,其中有两个参数
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 有三个或更多参数怎么办?那是合法的吗?第一个参数是否成为方法目标,其余成为参数?
我认为您正在寻找 JLS 部分 15.13.3,其中包括:
如果形式为
,则调用方法体同样具有编译时声明的方法调用表达式的作用,即方法引用表达式的编译时声明。方法调用表达式的运行时评估如 §15.12.4.3、§15.12.4.4 和 §15.12.4.5 中所述,其中:ReferenceType :: [TypeArguments] Identifier
调用方式源自§15.12.3中规定的编译时声明。
如果编译时声明的是实例方法,那么目标引用就是调用方法的第一个形参。否则,没有目标参考。
如果编译时声明是实例方法,则方法调用表达式的参数(如果有的话)是调用方法的第二个和后续形式参数。否则,方法调用表达式的参数是调用方法的形式参数。
基本上请注意最后两个项目符号。
例如,如果 lambda 有三个或更多参数怎么办?那是合法的吗?第一个参数是否成为方法目标,其余成为参数?
是的:)
我会在这里举几个例子,供那些觉得 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 期望该对象作为第一个参数 + 目标方法所需的任意数量的参数以相同的对应顺序。