Consider the following example, which is not compiled:
List<Integer> list = Arrays.asList(1, 2, -3, 8);
list.stream()
.filter(x -> x > 0)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll)
.stream() // Stream<Object>
.map(x -> x * 2)
.forEach(System.out::println);
If I replace
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll)
with
.collect(Collectors.toList())
The code will be compiled.
So the question is how do I write collect()
with supplier and accumulator(I need it) to be able to call a stream()
after it?
It appears that you've made a raw method reference to the ArrayList
constructor with ArrayList::new
.
The type argument was not inferred with:
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll)
The 3-argument overload of collect
expects 3 arguments, the first one being a Supplier<R>
. At this point there is no connection between the collect
method's type argument R
and T
which is Integer
here. The only way to infer this would be through the second argument, a BiConsumer<R, ? super T>
. Here you have ArrayList::add
, which gives the compiler no way to infer R
either.
You must supply what R
is in the first argument, the Supplier. You can supply explicit type arguments to the class to create on a method reference.
.collect(ArrayList<Integer>::new, ArrayList::add, ArrayList::addAll)
This compiles, and the output is as expected:
2
4
16
When you use Collectors.toList()
, you are supplying only one argument.
public static <T> Collector<T,?,List<T>> toList()
Here, there is only one type argument T
, so the compiler can correctly infer that this T
is Integer
, so a List<Integer>
is created, allowing the code to compile. The type arguments to the Collector
returned bind T
to List<T>
, allowing the compiler to perform the type inference.
Note that this is only necessary in the first place because there is no target type to help with type inference; you continue with the stream manipulation and just call System.out.println
at the end, which can take an Object
.
If you had this code:
List<Integer> modified = list.stream()
.filter(x -> x > 0)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
Then target type inference would have supplied Integer
for the type argument to ArrayList::new
. This compiles also.
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