As I know lambda expression can be replaced by method reference without any issues. My IDEs say the same, but the following example shows the opposite. The method reference clearly returns the same object, where as lambda expression returns new objects each time.
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Instance {
int member;
Instance set(int value){
this.member = value;
return this;
}
@Override
public String toString() {
return member + "";
}
public static void main(String[] args) {
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4);
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4);
List<Instance> collect1 = stream1.map(i -> new Instance().set(i)).collect(Collectors.toList());
List<Instance> collect2 = stream2.map(new Instance()::set).collect(Collectors.toList());
System.out.println(collect1);
System.out.println(collect2);
}
}
Here is my output:
[1, 2, 3, 4]
[4, 4, 4, 4]
Lambda expression is an anonymous method (method without a name) that has used to provide the inline implementation of a method defined by the functional interface while a method reference is similar to a lambda expression that refers a method without executing it.
Lambdas are clearer The method reference syntax could stand in for either one. It hides what your code is actually doing.
A lambda expression is a short form for writing an anonymous class. By using a lambda expression, we can declare methods without any name. Whereas, Anonymous class is an inner class without a name, which means that we can declare and instantiate class at the same time.
You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it's often clearer to refer to the existing method by name.
The timing of method reference expression evaluation differs from
which of lambda expressions.
With a method reference that has an expression (rather than a type) preceding the ::
the subexpression is evaluated immediately and the result of evaluation is stored and reused then.
So here :
new Instance()::set
new Instance()
is evaluated a single time.
From 15.12.4. Run-Time Evaluation of Method Invocation (emphasis is mine) :
The timing of method reference expression evaluation is more complex than that of lambda expressions (§15.27.4). When a method reference expression has an expression (rather than a type) preceding the :: separator, that subexpression is evaluated immediately. The result of evaluation is stored until the method of the corresponding functional interface type is invoked; at that point, the result is used as the target reference for the invocation. This means the expression preceding the :: separator is evaluated only when the program encounters the method reference expression, and is not re-evaluated on subsequent invocations on the functional interface type.
Your lambda expression is calling new Instance()
each time it's executed. This explains why the result of its toString()
is different for each element.
The method reference retains the instance off which it is referenced, such that it's similar to:
Instance instance = new Instance();
List<Instance> collect2 = stream2.map(instance::set).collect(Collectors.toList());
The result of using the method reference in this case is that the same instance is used to call set
, collected at the end. The member
value displayed is the one last set.
As an experiment, make these changes and observe that the instance is changing in the case of the lambda expression:
/* a random string assigned per instance */
private String uid = UUID.randomUUID().toString();
Instance set(int value) {
this.member = value;
System.out.println("uid: " + uid); //print the ID
return this;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With