Java 24 introduces a new method, gather(Gatherer), in the java.util.stream API, bringing powerful new capabilities to intermediate operations in streams.
What is a Gatherer?
A Gatherer is an intermediate stream operation that processes elements while considering their relationships with previous elements. Unlike map(), filter(), and flatMap(), which operate on single elements independently, Gatherer enables more complex transformations, such as folding functions, windowing, and concurrent processing.
Gatherer is an intermediate operation, whereas Collectors.collect() is a terminal operation.
Key Features of Gatherer
- New
gather(Gatherer)method added tojava.util.Streamin Java 24. - Allows processing of elements with context from previous elements.
- Supports various built-in functions like windowed transformations and concurrent mapping.
Structure of a Gatherer
A Gatherer consists of three parts:
- T – Type of input elements.
- A – Mutable state type (typically hidden as an implementation detail).
- R – Type of output elements.
Core Methods in Gatherer
Internally, a Gatherer operates using the following methods:
- initializer() (Optional) – Initializes the Gatherer.
- integrator() (Mandatory) – Integrates elements into the Gatherer.
- combiner() (Optional) – Merges two Gatherers.
- finisher() (Optional) – Defines the final processing step.
- andThen() (Optional) – Chains another Gatherer.
Built-in Gatherers
windowFixed(int windowSize)
Groups elements into fixed-size windows.
List<List<Integer>> windows = Stream.of(1,2,3,4,5,6,7,8)
.gather(Gatherers.windowFixed(3))
.toList();
// Output: [[1, 2, 3], [4, 5, 6], [7, 8]]
windowSliding(int windowSize)
Creates overlapping sliding windows.
List<List<Integer>> windowBy2 = Stream.of(1,2,3,4,5,6,7,8)
.gather(Gatherers.windowSliding(2))
.toList();
// Output: [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8]]
fold(Supplier<R> initial, BiFunction<R, T, R> folder)
Reduces a stream to a single element.
Optional<String> numberString = Stream.of(1,2,3,4,5,6,7,8,9)
.gather(Gatherers.fold(() -> "", (string, number) -> string + number))
.findFirst();
// Output: "123456789"
scan(Supplier<R> initial, BiFunction<R, T, R> scanner)
Performs a prefix scan on elements.
List<String> numberStrings = Stream.of(1,2,3,4,5,6,7,8,9)
.gather(Gatherers.scan(() -> "", (string, number) -> string + number))
.toList();
// Output: ["1", "12", "123", "1234", "12345", "123456", "1234567", "12345678", "123456789"]
mapConcurrent(int maxConcurrency, Function<T, R> mapper)
Executes a function in parallel using virtual threads.
With the introduction of gather(), Java Streams gain new flexibility in processing data efficiently and expressively. Stay tuned for more insights into Java 24 features!
Leave a comment