A stream gatherer transforms a sequence while retaining operation state, which lets a pipeline express batching and ordered accumulation beyond a one-element map.
Java stream gatherers: batching and ordered running totals
Java 25+. The program uses JDK classes and requires no preview flags.
State the output shape
A dispatch pipeline batches receipt quantities into fixed windows and then computes running totals for an audit trace. Those are different transformations: one emits lists, while the other emits an accumulated value for each input. A final reduce would return only the aggregate, losing the intermediate totals.
windowFixed emits a smaller final window when the input does not fill the requested size. An empty input produces no windows. Validate the batch size at the configuration boundary rather than discovering an invalid size after work has been admitted. The program checks the trailing batch and the empty stream.
Window lists are unmodifiable membership structures. Their element objects can still be shared mutable values. This fixture uses Integer values, so that particular ownership issue is absent. A batch of mutable receipt objects would need an explicit snapshot or transfer-of-ownership rule.
Know what retained output costs
The pipeline below materializes all windows with toList. An online consumer could process windows as they arrive, but returning every window retains the batch references. For running totals, the order of the input is part of the result. Do not substitute an order-dependent recurrence into an operation that assumes an interchangeable grouping rule.
Working program
import java.util.List;
import java.util.stream.Gatherers;
public class DispatchBatchGatherers {
public static void main(String[] args){
List<Integer> counts=List.of(4,7,2,9,3);
System.out.println(counts.stream().gather(Gatherers.windowFixed(2)).toList());
System.out.println(counts.stream().gather(Gatherers.scan(()->0,Math::addExact)).toList());
System.out.println(List.<Integer>of().stream().gather(Gatherers.windowFixed(2)).count());
}
}Output
[[4, 7], [2, 9], [3]]
[4, 11, 13, 22, 25]
0Costs and boundaries
Both transformations inspect n elements. Materializing the windows or every running total retains O(n) output. A configured large window can allocate substantial temporary storage even for a shorter stream. Gatherers are final from Java 24; this checked source targets Java 25 rather than earlier preview releases.
Common Mistakes
- A final partial window is valid output.
- Unmodifiable windows do not deep-copy arbitrary elements.
- toList still retains the complete returned result.
