JDK is introducing an API Stream.toList()
with JDK-8180352. Here is a benchmarking code that I have attempted to compare its performance with the existing Collectors.toList
:
@BenchmarkMode(Mode.All)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 20, time = 1, batchSize = 10000)
@Measurement(iterations = 20, time = 1, batchSize = 10000)
public class CollectorsVsStreamToList {
@Benchmark
public List<Integer> viaCollectors() {
return IntStream.range(1, 1000).boxed().collect(Collectors.toList());
}
@Benchmark
public List<Integer> viaStream() {
return IntStream.range(1, 1000).boxed().toList();
}
}
The result summary is as follows:
Benchmark Mode Cnt Score Error Units
CollectorsVsStreamToList.viaCollectors thrpt 20 17.321 ± 0.583 ops/s
CollectorsVsStreamToList.viaStream thrpt 20 23.879 ± 1.682 ops/s
CollectorsVsStreamToList.viaCollectors avgt 20 0.057 ± 0.002 s/op
CollectorsVsStreamToList.viaStream avgt 20 0.040 ± 0.001 s/op
CollectorsVsStreamToList.viaCollectors sample 380 0.054 ± 0.001 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p0.00 sample 0.051 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p0.50 sample 0.054 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p0.90 sample 0.058 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p0.95 sample 0.058 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p0.99 sample 0.062 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p0.999 sample 0.068 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p0.9999 sample 0.068 s/op
CollectorsVsStreamToList.viaCollectors:viaCollectors·p1.00 sample 0.068 s/op
CollectorsVsStreamToList.viaStream sample 525 0.039 ± 0.001 s/op
CollectorsVsStreamToList.viaStream:viaStream·p0.00 sample 0.037 s/op
CollectorsVsStreamToList.viaStream:viaStream·p0.50 sample 0.038 s/op
CollectorsVsStreamToList.viaStream:viaStream·p0.90 sample 0.040 s/op
CollectorsVsStreamToList.viaStream:viaStream·p0.95 sample 0.042 s/op
CollectorsVsStreamToList.viaStream:viaStream·p0.99 sample 0.050 s/op
CollectorsVsStreamToList.viaStream:viaStream·p0.999 sample 0.051 s/op
CollectorsVsStreamToList.viaStream:viaStream·p0.9999 sample 0.051 s/op
CollectorsVsStreamToList.viaStream:viaStream·p1.00 sample 0.051 s/op
CollectorsVsStreamToList.viaCollectors ss 20 0.060 ± 0.007 s/op
CollectorsVsStreamToList.viaStream ss 20 0.043 ± 0.006 s/op
Of course, the first question to the domain experts would be if the benchmarking procedure is correct or not? The test class was executed on MacOS. Do let me know for any further details required.
Follow-up, as far as I could infer from the readings the average time, throughput, and sampling time of the Stream.toList
looks better than the Collectors.toList
. Is that understanding correct?
Stream::toList
is built atop toArray
, not collect
. There are a number of optimizations in toArray
that make it potentially faster than collecting, though this depends heavily on the details. If the stream pipeline (from source through final intermediate operation) is SIZED
, the target array can be presized (rather than potentially reallocating as the toList
collector must do.) If the pipeline is further SUBSIZED
, then parallel executions can not only presize the result array, but can compute exact per-shard offsets so each sub-task can drop its results in exactly the right place, eliminating the need for copying intermediate results into the final result.
So, depending on the details, toList
may well be considerably faster than collect
.
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