Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Argument Mismatch when using the collect Stream method

The following code:

names = Arrays.asList("A","B","C").stream();
List<String> namesAsList = names.collect(() -> new ArrayList<String>(),List::add,List::add);
System.out.println("Individual Strings put into a list: " + namesAsList);

generates the following error during compilation:

List namesAsList = names.collect(() -> new ArrayList(),List::add,List::add); ^ (argument mismatch; invalid method reference incompatible types: ArrayList cannot be converted to int) where R,T are type-variables: R extends Object declared in method collect(Supplier,BiConsumer,BiConsumer) T extends Object declared in interface Stream 1 error

When I amend the code to remove the generic the code compiles with an unchecked expression warning:

Stream<String> names = Arrays.asList("A","B","C").stream();
List<String> namesAsList = names.collect(() -> new ArrayList(),List::add,List::add);
System.out.println("Individual Strings put into a list: " + namesAsList);

Why would I be receiving this error? I do not expect the problem to be relating to an int.

If the answer could include the way of figuring out the issue, this will be appreciated, so I can learn how to solve these problems myself.

like image 309
Christopher Barrett Avatar asked Jul 25 '17 08:07

Christopher Barrett


2 Answers

The method reference passed for combiner does not really fit. Try:

List<String> namesAsList = names
  .collect(ArrayList::new, List::add, List::addAll);

You passed the List::add and compiler is doing its best to try to interpret it as a combiner instance of BiConsumer type. Hence, the weird argument mismatch error.


Also, I assume you are implementing this only for research purposes. If you want to collect a Stream to a List, you can simply use:

.collect(Collectors.toList());

If you want to collect you Stream to ArrayList specifically, you can go for:

.collect(Collectors.toCollection(ArrayList::new));
like image 139
Grzegorz Piwowarek Avatar answered Oct 23 '22 19:10

Grzegorz Piwowarek


The problem is in the combiner, specifically: List::add should really be List::addAll.

Or more readable like this:

List<String> namesAsList = names.collect(
            () -> new ArrayList<>(), 
            List::add, 
            List::addAll);

You can re-write that with lambda expression when you are un-sure btw:

List<String> namesAsList = names.collect(
            () -> new ArrayList<>(),
            List::add,
            (List<String> left, List<String> right) -> {
                left.addAll(right);
            });

Notice that there are other problems as-well, like () -> new ArrayList<String>(), the type will be inferred by the compiler here, so no need for a <String>, like this: () -> new ArrayList<>(). Also this can be transformed to a method reference too: ArrayList::new, so ultimately it would be even simpler:

 List<String> namesAsList = names.collect(
            ArrayList::new,
            List::add,
            List::addAll);

This btw is the same thing that Collectors.toList does internally, so even further this can be simplified to:

List<String> namesAsList = names.collect(Collectors.toList());

The only problem is that the specification is free to change that (to return any other List besides ArrayList), so it could be written:

 List<String> namesAsList = names.collect(Collectors.toCollection(ArrayList::new));
like image 6
Eugene Avatar answered Oct 23 '22 18:10

Eugene