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.
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));
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));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With