The Java Streams API (introduced in Java 8) provides a modern, functional-style way to process collections of data. It allows you to work with sequences of elements (like List, Set, or arrays) using declarative operations such as filtering, mapping, reducing, collecting, and more, while supporting parallel execution.
Key Concepts
- Stream: A sequence of elements supporting sequential and parallel operations.
- Intermediate operations: Transform a stream into another stream (lazy operations). Examples:
filter(),map(),sorted(). - Terminal operations: Produce a result or a side-effect and end the stream pipeline. Examples:
collect(),forEach(),reduce().
Examples
1. Creating Streams
import java.util.*;
import java.util.stream.*;
public class StreamExamples {
public static void main(String[] args) {
// From a list
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Stream<String> stream1 = names.stream();
// From an array
String[] arr = {"one", "two", "three"};
Stream<String> stream2 = Arrays.stream(arr);
// Using Stream.of
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
// Infinite stream (example: odd numbers)
Stream<Integer> oddNumbers = Stream.iterate(1, n -> n + 2);
}
}
In Java, Streams (introduced in Java 8) provide a powerful way to work with collections and data processing using functional programming concepts. You can think of Stream functions as operating at different “levels” — from creation, through intermediate transformations, to terminal operations.
Here’s a breakdown of Stream functions by level 👇
🧩 1. Stream Creation (Source Level)
These functions create a stream from data sources like collections, arrays, or generators.
| Source Type | Example | Description |
|---|---|---|
| Collection | list.stream() | Creates a stream from a Collection (List, Set, etc.) |
| Arrays | Arrays.stream(arr) | Converts an array into a stream |
| Static Factory | Stream.of(1, 2, 3) | Creates a stream from given values |
| Infinite Stream | Stream.iterate(0, n -> n + 2) | Creates an infinite sequential stream |
| Random Stream | new Random().ints() | Stream of random ints, longs, doubles |
| File Stream | Files.lines(Path) | Reads lines from a file as a Stream |
⚙️ 2. Intermediate Operations (Transformation Level)
These return another stream, allowing chaining.
They are lazy — they don’t process data until a terminal operation is invoked.
| Function | Description | Example |
|---|---|---|
filter(Predicate) | Filters elements | stream.filter(x -> x > 10) |
map(Function) | Transforms each element | stream.map(String::toUpperCase) |
flatMap(Function) | Flattens nested streams | stream.flatMap(List::stream) |
distinct() | Removes duplicates | stream.distinct() |
sorted() | Sorts elements | stream.sorted() |
sorted(Comparator) | Custom sorting | stream.sorted(Comparator.reverseOrder()) |
peek(Consumer) | Performs an action for each element (for debugging/logging) | stream.peek(System.out::println) |
limit(long n) | Truncates the stream | stream.limit(5) |
skip(long n) | Skips first n elements | stream.skip(3) |
🎯 3. Terminal Operations (Execution Level)
These trigger the stream processing and produce a result (value, collection, or side effect).
| Function | Description | Example |
|---|---|---|
forEach(Consumer) | Iterates over elements | stream.forEach(System.out::println) |
collect(Collector) | Gathers elements into a collection or summary result | stream.collect(Collectors.toList()) |
toArray() | Converts to array | stream.toArray() |
reduce(...) | Reduces to a single value (sum, min, etc.) | stream.reduce(0, Integer::sum) |
count() | Counts elements | stream.count() |
findFirst() | Returns the first element (Optional) | stream.findFirst() |
findAny() | Returns any element (Optional) | stream.findAny() |
anyMatch(Predicate) | Returns true if any element matches | stream.anyMatch(x -> x > 10) |
allMatch(Predicate) | Returns true if all elements match | stream.allMatch(x -> x > 0) |
noneMatch(Predicate) | Returns true if no element matches | stream.noneMatch(x -> x < 0) |
min(Comparator) | Finds minimum | stream.min(Integer::compare) |
max(Comparator) | Finds maximum | stream.max(Integer::compare) |
🌊 Stream Processing Flow (Summary)
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
int result = numbers.stream() // 1️⃣ Stream Creation
.filter(n -> n % 2 == 0) // 2️⃣ Intermediate (filter)
.map(n -> n * n) // 2️⃣ Intermediate (map)
.reduce(0, Integer::sum); // 3️⃣ Terminal (reduce)
System.out.println(result); // Output: 56 (4 + 16 + 36)
🧠 Bonus: Parallel Streams
You can process streams in parallel for performance on multicore CPUs:
list.parallelStream()
.filter(...)
.map(...)
.collect(Collectors.toList());
