2

I am new to using lambdas and streams. I am trying to print an ArrayList that is sorted with duplicates removed, and formatted. I know that the following will work:

list.stream().distinct().forEach(System.out::print);

That will produce an output of ADFJKLXZ or whatever random Characters I have in list. However, what I want my output to look like is A, D, F, J, K, L, X, Z

I have tried this:

list.stream().distinct().forEach(System.out::printf("%s, ", ));

I think I probably still have some confusion on :: Why doesn't the above code work and what do I do to fix it?

Misha
  • 27,433
  • 6
  • 62
  • 78
L. Morrell
  • 45
  • 10

2 Answers2

5

You are attempting to pass a method reference while passing explicit parameters, which cannot be done. You can substitute a lambda expression instead.

list.stream().distinct().forEach(x -> System.out.printf("%s, ", x) );

This lambda expression is a Consumer that prints the character followed by a comma and a space.

If you would still like to use a method reference, then create your own method to wrap the printf call.

public static void printWithCommaSpace(Character c)
{
    System.out.printf("%s, ", c);
}

Then:

list.stream().distinct().forEach(YourClass::printWithCommaSpace);
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • That makes sense. So can :: only be used when there are no parameters to be passed? – L. Morrell Apr 07 '16 at 23:26
  • 2
    Method references can be used only when the signature matches the functional interface type expected by the method being called. In this case, `forEach` expects a `Consumer` that takes exactly one parameter. Nothing about a method reference passes explicit parameters, because a method reference doesn't equate semantically to the actual call of a method, just to an implementation of the functional interface that can be called later. – rgettman Apr 07 '16 at 23:29
  • 2
    Actually, when you use a method reference of the form `System.out::println` you are already binding a value, the `PrintStream` instance you found in `System.out`, on which the method will be invoked. So method references can bind at most one values and it will always be an object, on which the method will eventually invoked. See also [“What is the equivalent lambda expression for `System.out::println`?”](http://stackoverflow.com/a/28025717/2711488) – Holger Apr 08 '16 at 08:54
4

Because this is not how method references work, the single parameter has to match the captured value, which is not the case here.

How do you fix it? Use a lambda

list.stream().distinct().forEach(i -> System.out.printf("%s, ",i ));

Btw, a more concise way for doing it would be to use Collectors.joining

String collect = list.stream().collect(Collectors.joining(", "));

And now you don't have this extra comma at the end of the string

Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77