Java Stream API
The Stream API, introduced in Java 8, provides a powerful and expressive way to process sequences of data — such as collections or arrays — using a pipeline of operations. Streams make it possible to perform complex data processing (filtering, transforming, sorting, aggregating) in a clean, readable, and often single-expression style.
What is a Stream?
A stream is not a data structure — it does not store data. It is a pipeline through which data flows and is processed. Think of it like an assembly line in a factory — raw materials go in one end, pass through various processing stations, and a finished product comes out the other.
- Streams do not modify the original collection.
- A stream can only be consumed once.
- Streams support both sequential and parallel processing.
Stream Pipeline
A Stream pipeline consists of three parts:
- Source: The data source (Collection, Array, or generated sequence).
- Intermediate Operations: Transform or filter the stream. They are lazy — they do not run until a terminal operation is called.
- Terminal Operation: Produces a result or side effect and ends the pipeline.
collection.stream() // Source
.filter(...) // Intermediate
.map(...) // Intermediate
.collect(Collectors.toList()) // TerminalCreating a Stream
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
// From a List
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> stream1 = names.stream();
// From an Array
String[] arr = {"Java", "Python", "C++"};
Stream<String> stream2 = Arrays.stream(arr);
// Using Stream.of()
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);Intermediate Operations
filter() – Keep elements that match a condition
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
numbers.stream()
.filter(n -> n % 2 == 0)
.forEach(System.out::println); // 2 4 6 8 10map() – Transform each element
List<String> names = Arrays.asList("alice", "bob", "charlie");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println); // ALICE BOB CHARLIEsorted() – Sort elements
List<Integer> nums = Arrays.asList(5, 1, 8, 3, 7);
nums.stream()
.sorted()
.forEach(n -> System.out.print(n + " ")); // 1 3 5 7 8distinct() – Remove duplicates
Arrays.asList(1, 2, 2, 3, 3, 3, 4)
.stream()
.distinct()
.forEach(n -> System.out.print(n + " ")); // 1 2 3 4limit() and skip()
// limit: take first N elements
Stream.iterate(1, n -> n + 1)
.limit(5)
.forEach(n -> System.out.print(n + " ")); // 1 2 3 4 5
// skip: skip first N elements
Arrays.asList(10, 20, 30, 40, 50)
.stream()
.skip(2)
.forEach(n -> System.out.print(n + " ")); // 30 40 50peek() – View elements without modifying (useful for debugging)
Arrays.asList(1, 2, 3, 4, 5)
.stream()
.peek(n -> System.out.print("Before: " + n + " | "))
.filter(n -> n > 2)
.forEach(n -> System.out.println("After: " + n));Terminal Operations
forEach() – Perform an action on each element
List.of("Java", "is", "awesome")
.stream()
.forEach(System.out::println);collect() – Gather stream results into a collection
import java.util.stream.Collectors;
List<String> filtered = names.stream()
.filter(n -> n.length() > 3)
.collect(Collectors.toList());
System.out.println(filtered);count() – Count elements
long count = Arrays.asList(10, 25, 30, 45, 60)
.stream()
.filter(n -> n > 20)
.count();
System.out.println("Count: " + count); // 4reduce() – Combine elements into one result
int sum = Arrays.asList(1, 2, 3, 4, 5)
.stream()
.reduce(0, Integer::sum);
System.out.println("Sum: " + sum); // 15min() and max()
Optional<Integer> max = Arrays.asList(3, 1, 9, 5, 7)
.stream()
.max(Integer::compareTo);
System.out.println("Max: " + max.get()); // 9anyMatch(), allMatch(), noneMatch()
List<Integer> numbers = Arrays.asList(2, 4, 6, 8, 10);
System.out.println(numbers.stream().anyMatch(n -> n > 5)); // true
System.out.println(numbers.stream().allMatch(n -> n % 2 == 0)); // true
System.out.println(numbers.stream().noneMatch(n -> n < 0)); // trueComplete Example – Student Report Processing
import java.util.*;
import java.util.stream.*;
public class StreamExample {
public static void main(String[] args) {
List<String> students = Arrays.asList(
"Alice:85", "Bob:72", "Charlie:91", "Diana:60", "Eve:88"
);
// Step 1: Parse scores and filter passing students (marks >= 75)
// Step 2: Sort by score descending
// Step 3: Print top students
students.stream()
.map(s -> s.split(":"))
.filter(parts -> Integer.parseInt(parts[1]) >= 75)
.sorted((a, b) -> Integer.parseInt(b[1]) - Integer.parseInt(a[1]))
.forEach(parts -> System.out.println(parts[0] + " – " + parts[1]));
}
}Output:
Charlie – 91
Eve – 88
Alice – 85Parallel Streams
For large datasets, streams can be processed in parallel using parallelStream(), which utilizes multiple CPU cores automatically.
List<Integer> largeList = // ... large dataset
largeList.parallelStream()
.filter(n -> n % 2 == 0)
.forEach(System.out::println);Summary
- Stream API processes sequences of data through a pipeline: source → intermediate operations → terminal operation.
- Streams do not store data — they process it lazily.
- Key intermediate operations:
filter(),map(),sorted(),distinct(),limit(),skip(). - Key terminal operations:
forEach(),collect(),count(),reduce(),min(),max(). - Streams greatly reduce the amount of code needed for complex data transformations.
parallelStream()enables multi-core processing for large data sets.
