5 minutes
Devoxx BE 2025: It Only Starts with a Container & How Abstraction Becomes Reality
At Devoxx Belgium 2025, I was able to talk about what happens after you build your container. In theory, […]
Welcome to another Nugget Friday! Today, we’re excited to share some insights into a recent development in the Java ecosystem that promises to enhance the way we process data with streams, exploring how it can make your stream processing more flexible, efficient and expressive.
Since Java 8, the Java Stream API has been a powerful tool for processing collection data. However, it has its limitations. Sometimes, the built-in operations just don’t cut it, with software developers finding that the built-in operations don’t quite meet their needs. You might need a specific transformation that doesn’t exist, or you might find yourself resorting to clunky workarounds like intermediate lists or complex collectors.
Let’s consider a scenario where you want to group elements into fixed-size groups of three, keeping only the first two groups:
public static ArrayList<ArrayList<Integer>> groupInThrees(int size, int numGroups) {
return Stream.iterate(0, i -> i + 1)
.limit((long) size * numGroups)
.collect(Collector.of(
ArrayList::new,
(groups, element) -> {
if (groups.isEmpty() || groups.getLast().size() == size) {
groups.add(new ArrayList<>(List.of(element)));
} else {
groups.getLast().add(element);
}
},
(_, _) -> { throw new UnsupportedOperationException("Cannot be parallelized");
}
));
}
This code achieves the goal, but it’s quite verbose and hard to read. The custom collector within collect() adds unnecessary complexity.
Introduced as a preview feature in JDK 22, Java Stream Gatherers (JEP 461) provide a way to define custom intermediate operations, giving you the flexibility to create exactly what you need. Think of them as the “missing link” in the Stream API, allowing you to build pipelines that are more expressive and efficient.
Gatherers work by consuming elements from an input stream and producing elements for an output stream. They have four key functions:
To get you started, Java 22 provides several useful built-in stream gatherers:
With Stream Gatherers, we can rewrite our above examples as follows:
public static List<List<Integer>> findGroupsOfThreeWithGatherer(long fixed_size, int grouping) {
return Stream.iterate(0, i -> i + 1)
.gather(Gatherers.windowFixed((int)fixed_size)).limit(grouping)
.collect(Collectors.toList());
}
This code is smoother, concise and much easier to read.
Stream Gatherers are a great addition to the Java Language, especially given the pervasiveness of collections in Java applications. They open up a whole new world of possibilities, allowing you to tackle tasks that were previously difficult or impossible. So why not give them a try? Your code (and your future self) will thank you!
By integrating gatherers into your stream pipelines, you can achieve a level of customization and efficiency that was not possible with the traditional Stream API. This is particularly beneficial for complex data processing tasks that require unique transformations or aggregations. To learn more, you can read our detailed blog post on Stream Gatherers here.
Happy Friday and Happy Coding!
Share:
5 minutes
At Devoxx Belgium 2025, I was able to talk about what happens after you build your container. In theory, […]
5 minutes
Welcome aboard the October issue of The Monthly Catch!As the leaves turn and conference season hits full stride, the […]
2 minutes
How outdated Java systems are draining budgets and throttling innovation across financial services? Let’s dig in in this blog […]
The article is incredibly insightful! The ability to create custom intermediate operations truly enhances the flexibility and expressiveness of stream pipelines. It’s fascinating how gatherers can transform elements in various ways, track previously seen elements, and even short-circuit to handle infinite streams.
This feature opens up new possibilities for complex data processing tasks that were previously challenging to achieve with the traditional Stream API.