August 2026 · Java 24 / Java 26
Streams and Gatherers — Beyond Filter-Map-Collect
Exploring Java 24's Stream Gatherers API (JEP 485) and modern Java 26 intermediate transformations with built-in and custom gatherers.
The Evolution of Stream Pipelines
For over a decade since Java 8, the Java Streams API has provided expressive data processing pipelines with foundational operations: filter, map, flatMap, and terminal collectors. While effective for simple stateless pipelines, complex intermediate transformations—such as sliding windows, ordered batching, or stateful accumulation—traditionally forced developers back to imperative loops or verbose custom collectors.
Introduced in Java 24 via JEP 485 (and demonstrated on Java 26), Stream Gatherers introduce an extensible intermediate transformation mechanism through Stream.gather(), closing the expressive gap between standard stream operations and full custom reducers.
Where Gatherers Shine: Built-in Patterns
The standard library provides built-in gatherers in java.util.stream.Gatherers for common stateful and concurrency-controlled stream patterns:
- Sliding Window Analytics (
Gatherers.windowSliding): Computes moving averages, rolling extrema, and trend peak detection over overlapping windows. - Fixed-Size Batching (
Gatherers.windowFixed): Chunks continuous streams into discrete, fixed-size batches while preserving remainder elements. - Running & Cumulative Scans (
Gatherers.scan): Calculates prefix sums, running totals, and running maximums without losing stream composability. - Bounded-Concurrency Mapping (
Gatherers.mapConcurrent): Asynchronously maps elements across virtual threads with strict encounter-order preservation.
Custom Gatherers & State Machines
Beyond the built-in operations, developers can create custom gatherers by implementing Gatherer<T, A, R>, combining an initializer, integrator, combiner, and finisher. The reference suite demonstrates several advanced custom gatherers:
- Stream Zipping (
CustomGatherers.zip): Pairing elements from two independent streams index-wise. - Adjacent Deduplication (
CustomGatherers.dedupConsecutive): Collapsing consecutive duplicate elements on the fly without buffering the full dataset. - Stateful Early Termination (
CustomGatherers.takeUntilConsecutiveFailures): Halting stream consumption based on dynamic threshold criteria. - Stream Tokenizers (
CustomGatherers.parseTokenEvents): Parsing flat token sequences into structured domain events via stream-driven state machines.
The Repository
The complete educational reference suite, automated test suites, and custom gatherer implementations are available on GitHub:
github.com/lazarius-borg/java_gatherers
Demonstration suite designed for Java 24 (JEP 485) and verified on Java SE 26.