Instance Method Reference and Lambda Parameters

拟墨画扇 提交于 2019-12-17 05:11:12

问题


I am having trouble understanding the syntax for a method reference, where there are two parameters a and b, and the reference is to a method of a on b.

For example I understand how

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

is equivalent to

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

because in that case the lambda parameters match the method call parameters (o1, o2).

Howevever for this lambda

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

my IDE tells me that is equivalent to:

stream.sorted(String::compareToIgnoreCase);

and I am not finding a rule for replacing that syntax: a.method(b) with a method reference.

For example, what if there are three or more parameters to the lambda? Is that legal? Does the first parameter become the method target, and the remaining become the parameters?


回答1:


I think you're looking for JLS section 15.13.3, which includes:

If the form is ReferenceType :: [TypeArguments] Identifier, the body of the invocation method similarly 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.

  • If the compile-time declaration is an instance method, then the target reference is the first formal parameter of the invocation method. Otherwise, there is no target reference.

  • If the compile-time declaration is an instance method, then the arguments to the method invocation expression (if any) are the second and subsequent formal parameters of the invocation method. Otherwise, the arguments to the method invocation expression are the formal parameters of the invocation method.

Note the last two bullets, basically.

For example, what if there are three or more parameters to the lambda? Is that legal? Does the first parameter become the method target, and the remaining become the parameters?

Yup :)




回答2:


I would give a couple of examples here, for those who find Oracle documentation a bit hard to take in. Imagine you need a reference to a Comparator instance:

.sorted(String::compareTo)

String::compareTo is identical to:

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

Because, as Jon explained, a method reference will be transformed to a lambda that will expect 2 parameters. The actual arbitrary object passed in the stream as a first argument, and one more parameter(since Comparator expects int compare(T o1, T o2)). Another case:

.map(Employee::getSalary)

In this case map expects: Function. Function requires implementation of R apply(T var1) - a method with 1 argument. In this case the only parameter that will be passed to the lambda is the actual arbitrary object - instance on Employee.

To sum up - depending on the compile time context, method reference to arbitrary object will always be "transformed" into a lambda that expects that object as a first parameter + any number of parameters that the target method requires in the same corresponding order.



来源:https://stackoverflow.com/questions/25512532/instance-method-reference-and-lambda-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!