Skip to main content

9.4 Iterating with Java 8 Streams

Java Collections Framework: Iterating with Java 8 Streams

Overview of Java 8 Streams

Streams in Java 8 introduced a new, functional-style approach to processing collections of objects. A stream represents a sequence of elements that supports various methods to perform computations on data, such as filtering, mapping, and reducing, without modifying the underlying data source.

Key Features of Streams

  • Functional Operations: Supports filter, map, reduce, and more.
  • Lazy Evaluation: Operations on streams are only executed when necessary.
  • Parallel Processing: Enables parallelism to improve performance.

Creating Streams

Streams can be created from a variety of sources, such as collections, arrays, or even custom data sources.

Example: Creating a Stream from a List

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Creating a stream from a List
Stream<String> stream = names.stream();

// Iterating through the stream
stream.forEach(System.out::println); // Output: Alice, Bob, Charlie
}
}

In this example, we create a Stream from a List and use forEach to print each element.


Common Stream Operations

1. Filtering

The filter method allows you to exclude elements that don’t match a given condition.

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

public class FilterExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// Filter even numbers
numbers.stream()
.filter(n -> n % 2 == 0)
.forEach(System.out::println); // Output: 2, 4, 6
}
}

In this example, filter is used to keep only even numbers in the stream.

2. Mapping

The map function is used to transform each element in a stream.

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

public class MapExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Convert each name to uppercase
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println); // Output: ALICE, BOB, CHARLIE
}
}

Here, map is applied to each element, converting names to uppercase.

3. Reducing

The reduce method combines elements of a stream into a single result, often using an accumulator function.

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

public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Sum of all numbers
int sum = numbers.stream()
.reduce(0, Integer::sum);

System.out.println("Sum: " + sum); // Output: Sum: 15
}
}

In this example, reduce accumulates all integers in the list to compute their sum.


Parallel Streams

Parallel streams divide tasks across multiple threads, improving performance for large datasets.

Example: Using Parallel Stream

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

public class ParallelStreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Edward");

// Process stream in parallel
names.parallelStream()
.forEach(System.out::println); // Output order may vary due to parallel processing
}
}

Here, parallelStream enables concurrent processing of the stream’s elements.


Summary

  • Streams allow functional-style operations on collections, enabling clean and concise code.
  • Filtering, mapping, and reducing are common stream operations for data processing.
  • Parallel streams provide an easy way to leverage multi-core processors.

Streams in Java 8 are a powerful tool for handling data in a functional and efficient manner, especially when working with collections.