Java 9: filtering and flatmapping - Two new collectors for your Streams

If you've worked with streams you've probably played around with the Collectors class.

In earlier posts I've looked at how you can accumulate elements of a stream using Collectors as well as looking at how you can create a custom collector.

In this post we're going to take a look at two new collectors that have been introduced in Java 9 — the filtering method and the flatMapping method.

Filtering elements using Collectors.filtering

The Collectors.filtering method is quite simple. It allows us to filter out elements of a stream.

All you need to provide is the predicate you want to filter by and a succeeding collector that should be used to accumulate the filtered elements.

To see how this is done, say we got a stream of articles and we want to extract the ones that contain the tag "Java". We also want to get the final result as a Set.

  .collect(Collectors.filtering(article -> article.getTags().contains("Java"),

That's it! All we do is to provide our predicate followed by the Collectors.toSet() method when creating the filtering collector.

Now when that's said, it doesn't really make sense to use the Collectors.filtering in such a simple case. We could instead use Stream's own filter method.

The Collectors.filtering really starts to shine when it becomes part of another Collector.

As an example, say we first want to group the articles by publisher year, then use the filtering method to keep only Java articles.

    Collectors.filtering(article -> article.getTags().contains("Java"), Collectors.toSet())));

Flattening using Collectors.flatMapping

Another new method is the Collectors.flatMapping.

It behaves as a normal flatmap, allowing you to flatten the stream.

Say we want to collect all tags that are found in our articles and return them as a Set.

  .collect(Collectors.flatMapping(article -> article.getTags().stream(),

There we go — our tags are extracted. The first thing we provide to Collectors.flatMapping is the flattening function that defines how to extract the tags and make them into a stream. The second thing we provide is the succeeding Collector, which in our case is toSet. The reason for making it into a Set is that it'll remove duplicate tags.

As with the filtering, this first example is a bit pointless since the Stream API offer a flatMap function as well.

Now, if we use it as part of another Collector, we see the real benefit of the Collectors.flatMapping method.

Again, let's make the flatMapping collector a part of the Collectors.groupingBy.

Say we want to figure out what tags have been used in the different publishing years.

      Collectors.flatMapping(article -> article.getTags().stream(), Collectors.toSet())));

As with the filtering method, we first group the articles by publishing year, then we use the flatMapping method to flatten the articles to tags.

As you can see, the Stream API continues to be strengthened, and I find it refreshing to see the commitment to make these functional aspects even better.