(This is probably related to https://stackoverflow.com/a/30312177/160137, but I'm afraid I still don't get it. So I'm asking my question this way, in the hope that it'll lead to an answer I can more easily understand.)
Normally when I have a Stream I can convert it to a collection using one of the static methods in the Collectors class:
List<String> strings = Stream.of("this", "is", "a", "list", "of", "strings")
.collect(Collectors.toList());
The similar process doesn't work on primitive streams, however, as others have noticed:
IntStream.of(3, 1, 4, 1, 5, 9)
.collect(Collectors.toList()); // doesn't compile
I can do this instead:
IntStream.of(3, 1, 4, 1, 5, 9)
.boxed()
.collect(Collectors.toList());
or I can do this:
IntStream.of(3, 1, 4, 1, 5, 9)
.collect(ArrayList<Integer>::new, ArrayList::add, ArrayList::addAll);
The question is, why doesn't Collectors.toList() just do that for primitive streams? Is it that there's no way to specify the wrapped type? If so, why doesn't this work either:
IntStream.of(3, 1, 4, 1, 5, 9)
.collect(Collectors.toCollection(ArrayList<Integer>::new)); // nope
Any insight would be appreciated.
Well, it would be no problem to let IntStream
provide a method with the signature<R,A> R collect(Collector<? super Integer,A,R> collector)
performing an implicit boxing. It could be implemented as simple as return boxed().collect(collector);
.
The question is “why should it” or the other way round: why do the primitive stream specializations exist at all?
They merely exist for performance reasons, to offer stream operations without boxing overhead. So it’s an obvious design decision not to include any operation which already exists in the generic Stream
interface as for all these you can simply invoke boxed().genericOperation(…)
.
The answer, you have linked addresses a related, but different idea. It’s about providing a collect
method not accepting the generic Collector
, but a primitive specialization like Collector.ofInt
which could collect int
values without boxing, but for a collector which produces a List<Integer>
, unavoidably containing boxed values, it wouldn’t have any benefit.
Amongst the prebuilt collectors, only a few really could avoid boxing. All of them are provided as explicit terminal operations on the primitive streams (count()
, sum()
, min()
, max()
, summaryStatistics()
, …)
It’s a trade-off between number of classes/interfaces and potential performance gain. In the case of streams in general, the decision was to create IntStream
, LongStream
and DoubleStream
, but in case of the collectors, the decision was not to add such specializations.
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