Java Streams (Java 8+)
Java Streams were introduced in Java 8 to simplify data processing on collections by providing a declarative, functional-style API.
Streams are not data structures —
they are operations performed on data.
Why Streams Were Introduced
Before Java 8:
- Data processing required loops
- Code was verbose and error-prone
- Parallel processing was complex
Streams solve this by providing:
- Clean and readable code
- Internal iteration
- Built-in parallelism
- Functional programming style
What Is a Stream?
A Stream is a sequence of elements from a source that supports data processing operations.
Important Clarification
- Streams do not store data
- Streams operate on data from a source
- Source can be:
- Collection
- Array
- I/O channel
Characteristics of Streams
- Streams do not modify the source
- Streams are not reusable
- Streams support lazy evaluation
- Streams process elements only when needed
- Streams support parallel execution
Internal Iteration
Collections:
for (String s : list) { }
Streams:
list.stream().filter(…).map(…);
✔ Iteration handled internally
✔ Less boilerplate
✔ Safer parallel execution
Stream Pipeline Structure
A stream pipeline consists of:
- Source
- Intermediate operation(s)
- Terminal operation
Source → Intermediate Ops → Terminal Op
Without a terminal operation:
- Nothing executes.
Intermediate Operations (return Stream)
| Method | Input | Output | Use Case | Example |
|---|---|---|---|---|
filter | Predicate | Stream | Select elements | p -> p.getAge() > 30 |
map | Function | Stream | Transform data | Player::getName |
flatMap 🚨 | Function<T, Stream | Stream | Flatten nested collections | team -> team.getPlayers().stream() |
sorted | Comparator | Stream | Sort elements | Comparator.comparingInt(Player::getAge) |
distinct | — | Stream | Remove duplicates | .distinct() |
limit | long | Stream | Get first N elements | .limit(3) |
skip | long | Stream | Skip first N | .skip(2) |
peek ⚠️ | Consumer | Stream | Debugging | .peek(System.out::println) |
Terminal Operations (end the stream)
| Method | Output | Use Case | Example |
|---|---|---|---|
toList() | List | Collect results | .toList() |
collect() | Any | Custom collection/result | Collectors.groupingBy(...) |
forEach ⚠️ | void | Perform action | .forEach(System.out::println) |
count | long | Count elements | .count() |
anyMatch | boolean | Any match condition | .anyMatch(p -> p.getAge() > 40) |
allMatch | boolean | All match condition | .allMatch(...) |
noneMatch | boolean | No match | .noneMatch(...) |
findFirst | Optional | First element | .findFirst() |
findAny | Optional | Any element | .findAny() |
max | Optional | Maximum element | .max(Comparator...) |
min | Optional | Minimum element | .min(Comparator...) |
reduce 🚨 | Optional | Combine elements | .reduce(Integer::sum) |
Collectors Cheat Sheet
Basic Collectors
| Method | Output | Use Case | Example |
|---|---|---|---|
toList() | List | Collect to list | Collectors.toList() |
toSet() | Set | Remove duplicates | Collectors.toSet() |
joining() | String | Join strings | joining(", ") |
Grouping & Aggregation
| Method | Output | Use Case | Example |
|---|---|---|---|
groupingBy | Map<K, List | Group data | groupingBy(Player::getRole) |
groupingBy + counting | Map<K, Long> | Count per group | groupingBy(role, counting()) |
groupingBy + mapping 🚨 | Map<K, List | Transform inside group | mapping(Player::getName, toList()) |
groupingBy + maxBy | Map<K, Optional | Max per group | maxBy(comparator) |
Advanced Collectors
| Method | Output | Use Case | Example |
|---|---|---|---|
partitioningBy | Map<Boolean, List | Split into 2 groups | p -> p.getAge() > 35 |
collectingAndThen 🚨 | Any | Post-process result | Optional::get |
mapping 🚨 | Collector | Transform inside grouping | mapping(name, toList()) |
counting | Long | Count elements | counting() |
maxBy / minBy | Optional | Find max/min | maxBy(comparator) |
Key Patterns
| Problem Type | Pattern |
|---|---|
| Nested list | flatMap |
| Filter data | filter |
| Transform data | map |
| Group data | groupingBy |
| Count | count() or counting() |
| Top element | max() |
| Boolean check | anyMatch() |
| Top per group | groupingBy + maxBy |