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