48. Streams — Gatherers (Java 22+)
Stream.gather(Gatherer) (Java 22+) adds a powerful stateful intermediate operation API — enabling sliding windows, prefix-while, deduplication by key, and other patterns that filter/map cannot express.
Explanation
The Stream intermediate operation API (filter, map, flatMap) is stateless — each element is processed independently. Some useful operations require state across elements: a sliding window needs to remember previous elements; takeWhile is already there but custom prefix predicates are awkward.
Gatherer<T,A,R> (JEP 461, standard Java 24) is the generalisation: it defines an optional initialiser (create state), an integrator (process each element, emit zero or more downstream), an optional combiner (for parallel use), and a finisher (emit anything left in state). Built-in gatherers are in java.util.stream.Gatherers: windowFixed(n), windowSliding(n), scan(identity, fn) (running accumulation), fold(identity, fn), mapConcurrent(n, fn).
Example
import java.util.List;
import java.util.stream.Gatherers;
public class StreamsGatherers {
public static void main(String[] args) {
// windowFixed: non-overlapping windows of size 3
List<List<Integer>> fixed = java.util.stream.Stream.iterate(1, n -> n + 1)
.limit(9)
.gather(Gatherers.windowFixed(3))
.toList();
System.out.println("Fixed windows: " + fixed);
// [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// windowSliding: overlapping windows of size 3
List<List<Integer>> sliding = java.util.stream.Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowSliding(3))
.toList();
System.out.println("Sliding windows: " + sliding);
// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// scan: running sum
List<Integer> runningSum = java.util.stream.Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.scan(() -> 0, Integer::sum))
.toList();
System.out.println("Running sum: " + runningSum);
// [1, 3, 6, 10, 15]
// fold: like reduce but emits final value (not every intermediate)
var total = java.util.stream.Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.fold(() -> 0, Integer::sum))
.findFirst();
System.out.println("Fold total: " + total); // Optional[15]
}
}Sources
- https://openjdk.org/jeps/461 — JEP 461: Stream Gatherers (preview Java 22)
- https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/util/stream/Gatherers.html — Gatherers API
- https://openjdk.org/jeps/485 — JEP 485: Stream Gatherers (standard, Java 24)