Which Java List Conversion Is Faster? Stream.toList vs Collectors.toList Benchmarked
This article compares the performance of Java 16’s Stream.toList(), Collectors.toList() and Collectors.toUnmodifiableList() by running JMH benchmarks on different data sizes, revealing that Stream.toList() consistently outperforms the others in throughput, average latency, and cold‑start time.
Yesterday I introduced the Stream enhancements in Java 16, which allow converting a stream directly to a List via toList().
The main conversion methods are:
list.stream().toList();
list.stream().collect(Collectors.toList());
list.stream().collect(Collectors.toUnmodifiableList());Readers often ask about the difference between Stream.toList() and Collectors.toList() and which performs better.
The differences are: Stream.toList() returns an immutable list that cannot be modified. Collectors.toList() returns a mutable list. Collectors.toUnmodifiableList() also returns an immutable list.
To compare performance, I ran JMH benchmarks.
Benchmark with 1,000 elements
@BenchmarkMode(Mode.All)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 20, time = 1, batchSize = 10000)
@Measurement(iterations = 20, time = 1, batchSize = 10000)
public class BenchmarkStreamToList {
@Benchmark
public List<Integer> streamToList() {
return IntStream.range(1, 1000).boxed().toList();
}
@Benchmark
public List<Integer> collectorsToList() {
return IntStream.range(1, 1000).boxed().collect(Collectors.toList());
}
@Benchmark
public List<Integer> collectorsToUnmodifiableList() {
return IntStream.range(1, 1000).boxed().collect(Collectors.toUnmodifiableList());
}
}Result summary:
Benchmark Mode Cnt Score Error Units
BenchmarkStreamToList.collectorsToList thrpt 20 24.422 ± 0.268 ops/s
BenchmarkStreamToList.collectorsToUnmodifiableList thrpt 20 22.784 ± 0.599 ops/s
BenchmarkStreamToList.streamToList thrpt 20 31.779 ± 1.732 ops/s
...From the report:
Throughput: streamToList > collectorsToList > collectorsToUnmodifiableList Average latency: same order.
p0.9999 latency: streamToList > collectorsToUnmodifiableList > collectorsToList Cold‑start latency: streamToList > collectorsToList > collectorsToUnmodifiableList Thus, Stream.toList() performs better in all measured aspects.
Benchmark with 10,000 elements
@Benchmark
public List<Integer> streamToList() {
return IntStream.range(1, 10000).boxed().toList();
}
@Benchmark
public List<Integer> collectorsToList() {
return IntStream.range(1, 10000).boxed().collect(Collectors.toList());
}
@Benchmark
public List<Integer> collectorsToUnmodifiableList() {
return IntStream.range(1, 10000).boxed().collect(Collectors.toUnmodifiableList());
}Result summary:
Benchmark Mode Cnt Score Error Units
BenchmarkStreamToList.collectorsToList thrpt 20 2.186 ± 0.162 ops/s
BenchmarkStreamToList.collectorsToUnmodifiableList thrpt 20 2.184 ± 0.042 ops/s
BenchmarkStreamToList.streamToList thrpt 20 3.538 ± 0.058 ops/s
...The same ordering holds: streamToList outperforms the other two methods in throughput, average time, and high‑percentile latencies, even when the collection size grows.
In conclusion, for converting a stream to a list, Stream.toList() is the most efficient choice.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
