Java Stream vs ParallelStream

Java Stream vs ParallelStream: A Detailed Comparison with Code Examples

Java Streams, introduced in Java 8, revolutionized the way we process collections of data. Streams allow developers to write concise, readable code to perform aggregate operations like filtering, mapping, and reducing on collections. A major feature of Java Streams is the ability to run operations either sequentially or in parallel. This brings us to two important concepts: Stream (sequential) and ParallelStream (parallel).

Java Stream vs ParallelStream: A Detailed Comparison with Code Examples
Java Stream vs ParallelStream: A Detailed Comparison with Code Examples


In this blog post, we will explore the differences between Java Stream and ParallelStream, when to use each, and provide clear code examples to illustrate their usage.

What is Java Stream?

A Java Stream is a sequence of elements supporting sequential and parallel aggregate operations. It processes elements one by one in a single thread.

  • Sequential Stream processes data >in order< on a single core.
  • It is simpler and guarantees the order of execution.
  • Suitable for tasks where order matters or tasks are lightweight.

Creating a Sequential Stream

You can create a sequential stream from a collection using .stream():

import java.util.Arrays;
import java.util.List;

public class SequentialStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        
        numbers.stream()
               .filter(n -&gt; n % 2 == 0)
               .forEach(System.out::println); // Output: 2 4
    }
}

What is Java ParallelStream?

ParallelStream performs operations in parallel using multiple threads, leveraging the multi-core architecture of modern processors.

  • The collection is divided into multiple substreams.
  • Each substream is processed concurrently on different CPU cores.
  • Final result combines these concurrent computations.
  • Execution order is not guaranteed.
  • Best used for large, CPU-intensive tasks where the processing order is unimportant.

Creating a Parallel Stream

You can create a parallel stream in two ways:

  1. Convert an existing sequential stream with .parallel():
numbers.stream()
       .parallel()
       .filter(n -&gt; n % 2 == 0)
       .forEach(System.out::println);
  1. Directly create a parallel stream from a collection:
numbers.parallelStream()
       .filter(n -&gt; n % 2 == 0)
       .forEach(System.out::println);

Key Differences Between Stream and ParallelStream

Feature Stream (Sequential) ParallelStream
Execution Single-threaded, sequential execution Multi-threaded, parallel execution
CPU Core Utilization Uses 1 core Uses multiple CPU cores
Order of Output Maintains order Order not guaranteed
Performance Slower for large or CPU intensive tasks Faster for large scale/CPU intensive tasks
Overhead Low Higher due to thread management
Use Case Ordered, dependent, or lightweight tasks Independent, unordered, or heavy tasks
Error Prone Less prone to concurrency issues More prone to concurrency issues

When to Use ParallelStream?

  • When processing large datasets.
  • When each element can be processed independently.
  • When order of processing/output doesn&#39;t matter.
  • When you want to improve performance by utilizing multiple CPU cores.

Avoid parallel streams if:

  • The order of processing matters.
  • The task is IO-bound or small/simple.
  • You have shared mutable state without proper synchronization.

ParallelStream Code Example

import java.util.Arrays;
import java.util.List;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List<String> letters = Arrays.asList("a", "b", "c", "d", "e");

        letters.parallelStream()
               .forEach(System.out::println); // Output order may vary
    }
}

Output (order may not be a,b,c,d,e):

c
a
e
b
d

Performance Comparison Example

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class StreamPerformanceExample {
    public static void main(String[] args) {
        List<Integer> numbers = IntStream.rangeClosed(1, 1_000_000).boxed().collect(Collectors.toList());

        // Sequential Stream
        long start1 = System.currentTimeMillis();
        long sum1 = numbers.stream()
                           .mapToLong(Integer::longValue)
                           .sum();
        long end1 = System.currentTimeMillis();
        System.out.println("Sequential stream sum: " + sum1 + " in " + (end1 - start1) + " ms");

        // Parallel Stream
        long start2 = System.currentTimeMillis();
        long sum2 = numbers.parallelStream()
                           .mapToLong(Integer::longValue)
                           .sum();
        long end2 = System.currentTimeMillis();
        System.out.println("Parallel stream sum: " + sum2 + " in " + (end2 - start2) + " ms");
    }
}

This example sums one million integers and you will often see the parallel stream finishing faster, especially on multi-core systems.

Summary

  • Java Stream is sequential, easier to debug, and preserves order.
  • Java ParallelStream splits tasks across multiple cores for faster execution at the cost of unordered results and potential overhead.
  • Choose parallel streams for computationally intensive, independent tasks.
  • Use sequential streams when order and simplicity are priorities.

This understanding will help write efficient, multi-core aware Java applications that leverage the power of Java 8+ streams effectively.

This blog post covered a detailed comparison of Java Stream vs ParallelStream with practical code examples and guidance on when to choose each one.

If you want code snippets or explanation on any specific part of the Java Streams, feel free to ask!

Previous Post Next Post

Blog ads

ads