When Is Java Stream Faster Than Traditional Loops? A Performance Comparison
This article explains Java 8 Stream fundamentals, compares intermediate and terminal operations, outlines its advantages over collections, and presents benchmark results showing when streams outperform iterator loops, especially with large data sets and parallel execution.
Stream is a new abstraction added in Java SE 8, defined in java.util.stream, representing a sequence of values and providing a rich set of aggregate operations that can replace many Collection manipulations.
Types of Stream Operations
① Intermediate operations
All processing steps applied to the data source after it enters the pipeline are called intermediate operations.
Intermediate operations return another Stream, allowing them to be chained.
Common intermediate operations include filter, distinct, map, sorted, etc.
② Terminal operations
After all intermediate operations are defined, a terminal operation is required to pull the data out of the pipeline.
Terminal operations can produce a result, convert the stream to a collection, array, String, and so on.
Characteristics of Streams
Can be traversed only once; after an element passes through the pipeline it cannot be processed again without creating a new stream.
Use internal iteration: the stream controls the iteration, which is generally more efficient than external iteration with an Iterator.
Advantages Over Collections
No storage: a stream does not store values; elements are produced from a data source on demand.
Functional style: operations produce a result without modifying the underlying data source.
Lazy evaluation: most operations are evaluated lazily, enabling short‑circuiting and higher efficiency.
Unbounded: streams can represent infinite sequences, unlike finite collections.
Concise code: stream pipelines often replace verbose iterator loops.
Efficiency Comparison Between Stream and Iterator
In small data sets, traditional iterator loops are faster; for large data sets, especially on multi‑core CPUs, parallel streams can outperform iterators.
Test Environment
System: Ubuntu 16.04 xenial
CPU: Intel Core i7‑8550U
RAM: 16 GB
JDK version: 1.8.0_151
JVM: HotSpot 64‑Bit Server VM (build 25.151‑b12)
JVM Settings:
-Xms1024m
-Xmx6144m
-XX:MaxMetaspaceSize=512m
-XX:ReservedCodeCacheSize=1024m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=100Benchmark Tests
1. Mapping
Increment each element of a random List and collect into a new List.
//stream
List<Integer> result = list.stream()
.mapToInt(x -> x)
.map(x -> ++x)
.boxed()
.collect(Collectors.toCollection(ArrayList::new));
//iterator
List<Integer> result = new ArrayList<>();
for (Integer e : list) {
result.add(++e);
}
//parallel stream
List<Integer> result = list.parallelStream()
.mapToInt(x -> x)
.map(x -> ++x)
.boxed()
.collect(Collectors.toCollection(ArrayList::new));2. Filtering
Select elements greater than 200.
//stream
List<Integer> result = list.stream()
.mapToInt(x -> x)
.filter(x -> x > 200)
.boxed()
.collect(Collectors.toCollection(ArrayList::new));
//iterator
List<Integer> result = new ArrayList<>(list.size());
for (Integer e : list) {
if (e > 200) {
result.add(e);
}
}
//parallel stream
List<Integer> result = list.parallelStream()
.mapToInt(x -> x)
.filter(x -> x > 200)
.boxed()
.collect(Collectors.toCollection(ArrayList::new));3. Natural Sorting
Sort the list using the natural order.
//stream
List<Integer> result = list.stream()
.mapToInt(x -> x)
.sorted()
.boxed()
.collect(Collectors.toCollection(ArrayList::new));
//iterator
List<Integer> result = new ArrayList<>(list);
Collections.sort(result);
//parallel stream
List<Integer> result = list.parallelStream()
.mapToInt(x -> x)
.sorted()
.boxed()
.collect(Collectors.toCollection(ArrayList::new));4. Reduction (Max)
Find the maximum value.
//stream
int max = list.stream()
.mapToInt(x -> x)
.max()
.getAsInt();
//iterator
int max = -1;
for (Integer e : list) {
if (e > max) {
max = e;
}
}
//parallel stream
int max = list.parallelStream()
.mapToInt(x -> x)
.max()
.getAsInt();5. String Joining
Join elements with commas.
//stream
String result = list.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
//iterator
StringBuilder builder = new StringBuilder();
for (Integer e : list) {
builder.append(e).append(",");
}
String result = builder.length() == 0 ? "" : builder.substring(0, builder.length() - 1);6. Mixed Operations
Filter nulls, add 1, filter >200, remove duplicates.
//stream
List<Integer> result = list.stream()
.filter(Objects::nonNull)
.mapToInt(x -> x + 1)
.filter(x -> x > 200)
.distinct()
.boxed()
.collect(Collectors.toCollection(ArrayList::new));
//iterator
HashSet<Integer> set = new HashSet<>(list.size());
for (Integer e : list) {
if (e != null && e > 200) {
set.add(e + 1);
}
}
List<Integer> result = new ArrayList<>(set);
//parallel stream
List<Integer> result = list.parallelStream()
.filter(Objects::nonNull)
.mapToInt(x -> x + 1)
.filter(x -> x > 200)
.distinct()
.boxed()
.collect(Collectors.toCollection(ArrayList::new));Experiment Summary
For small data sizes (≤ 1000), iterator loops are slightly faster, but the difference is sub‑millisecond and negligible for most business logic; streams improve readability.
For large data sizes (> 10 000), streams—especially parallel streams on multi‑core CPUs—outperform iterators, though typical applications rarely need to process millions of elements.
Parallel streams depend heavily on CPU core availability; without enough cores, their overhead can make them slower than sequential streams.
Recommendations for Using Streams
Use iterator for simple single‑step loops; prefer streams for multi‑step pipelines to gain readability with minimal performance loss.
Avoid parallel streams on single‑core machines; use them on multi‑core systems with large data sets.
When a stream contains boxed types, convert to primitive streams before intermediate operations to reduce boxing/unboxing overhead.
For debugging difficulties, refer to external resources such as “Java 8 Stream debugging methods”.
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.
