Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sonar : Replace this lambda with a method reference

This code sample

Collection<Number> values = transform(
        getValuatedObjects(),
        input -> getValueProvider().apply(input).getValue());

violates the Sonarqube rule:

Lambdas should be replaced with method references

Is it a sonar bug? Or can I really use a method reference?

like image 488
gontard Avatar asked Sep 01 '14 13:09

gontard


People also ask

How do you convert lambda expression to method?

To make the code clearer, you can turn that lambda expression into a method reference: Consumer<String> c = System. out::println; In a method reference, you place the object (or class) that contains the method before the :: operator and the name of the method after it without arguments.

How do I change lambda with method reference in eclipse?

apply(input). getValue() with a method reference without changing the semantics. A method reference replace a single method invocation, so it can't simply replace a lambda expression consisting of more than one method invocation. A lambda expression of the form input -> getValueProvider().

Can we replace lambda expression with method reference?

If you are using a lambda expression as an anonymous function but not doing anything with the argument passed, you can replace lambda expression with method reference. In the first two cases, the method reference is equivalent to lambda expression that supplies the parameters of the method e.g. System.

What is the difference between lambda expression and method reference?

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.


2 Answers

You can’t replace the lambda input -> getValueProvider().apply(input).getValue() with a method reference without changing the semantics.

A method reference replace a single method invocation, so it can’t simply replace a lambda expression consisting of more than one method invocation.

A lambda expression of the form input -> getValueProvider().apply(input) could be replaced by getValueProvider()::apply if, and only if, the evaluation time of getValueProvider() does not matter as in the lambda form the method is invoked on each lambda body evaluation while for the method reference it is invoked only once and the result captured.

This is similar to the difference between x -> System.out.println(x) and System.out::println where reading the contents of the field System.out happens at different times but usually it doesn’t matter. But you should be aware of the difference.

In your example, a third method getValue() is invoked. The only way to express that with method references needs a functional interface like Function which has methods like andThen and/or compose. However, the way Java 8 works, that would require casting the first method reference to the target interface to invoke the combining method which would be by no way easier to read that the lambda expression you have now: ((Function<X,Y>)getValueProvider()::apply).andThen(Y::getValue) where Y is the type, apply(input) returns.

Note that the rule says “Replace lambdas with method references when possible” which gives you room to say, “well, here it is impossible”, however, I’m not sure how much you can call it a “rule” then…

like image 195
Holger Avatar answered Sep 18 '22 15:09

Holger


list.stream().sorted().collect(Collectors.toList()).forEach(element -> operate(element));

replace the above lambda with a method reference.

list.stream().sorted().collect(Collectors.toList()).forEach(this::operate);

like image 27
Akanksha gore Avatar answered Sep 18 '22 15:09

Akanksha gore