Search code examples
javasonarqube

Sonar : Replace this lambda with a method reference. When should "stream()" be used?


I would like to know what is the difference between these two three pieces of code:

underlyingConnectors.values().stream().forEach(connector -> connector.start());

underlyingConnectors.values().forEach(connector -> connector.start());

underlyingConnectors.values().forEach(Connector::start);

The second line compiles fine but my Ecplipse IDE complains with "Sonar : Replace this lambda with a method reference".

How do I choose the approriate code to use? Is there a specific use case for each of these?


Solution

  • The second one is simply a shorthand notation for the first one and the third one for the second one. A rule of thumb is that if a method has no parameters like the second one you can simply replace it with a notation like the third one.

    More generally, if the expression on the right-hand side (RHS) of a lambda expression is a method call on the left-hand side (LHS) of the lambda expression that needs no additional parameters or is a method call that takes only the left-hand side of the expression as a parameter that lambda-expression can then be replaced with a method reference - as soon as the RHS takes two parameters it is not as "pretty" as Java does not support currying of methods at the moment as a language feature but that can be replaced with wrappers:

    package com.example;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Consumer;
    
    public class Application {
    
      private static final String LINEBREAK = System.lineSeparator();
    
      public static void main(String[] args) {
        final List<String> strings = Arrays.asList("Hello", "World", "!");
    
        strings.forEach(string -> System.out.print(string + LINEBREAK)); // 1
    
        strings.forEach(string -> Application.printWithLineBreakParameter(LINEBREAK).accept(string)); // 2
    
        strings.forEach(Application.printWithLineBreakParameter(LINEBREAK)); // 3
      }
    
      private static Consumer<String> printWithLineBreakParameter(final String lineBreak) {
        return (string) -> System.out.print(string + lineBreak);
      }
    }
    

    Here, all three calls are equal but 2 can be replaced with 3 making it look neater than 1.