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());