-1

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?

Muhamad Gafar
  • 409
  • 3
  • 12

4 Answers4

1

The first line contains an unnecessary call to stream() and the two latter ones are a matter of opinion. If you want to write the shortest and most succinct code, you would use the last one. All of them work in an equivalent way and it's mainly about style.

The stream() is unnecessary since values() returns a Collection which extends Iterable which has forEach(Consumer<? super T> action) already.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
1

You can ommit the .stream() if you're just doing one operation with every element through .forEach(). Calling .stream() is redundant.

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

Line 2 is correct.

If you're just applying one operation to every entry, then just use the method reference, no need to write a lambda. This is basically a shorthand.

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

Line 2 is correct.

Dropout
  • 13,653
  • 10
  • 56
  • 109
1

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.

Smutje
  • 17,733
  • 4
  • 24
  • 41
0

Both lines are correct. It is just a warning of sonar lint. The method reference is a simple form of lambda, in case you are returning just a method.

jzProg
  • 279
  • 1
  • 2
  • 8