Hey, tea lovers! Today I will be talking about the partitioningBy Collector method of Stream API. I will be focusing on what is partitioningBy method, where and how to use it with different examples. I have already discussed How to use groupingBy Collector in Java Streams. Both partitioningBy and groupingBy are the
partitioningBy is a terminal operation of the Stream API pipeline.
The partitioningBy is the Stream API method, so obviously you should be familiar with Stream API along with functional programming with Java. Don’t worry if you don’t know about it, you can check the Functional Interfaces To Become More Functional in Java and Stream API: The Hero Without a Cape post in the same order. These posts will be enough for you to get started.
If you still have some questions, you can ask me in the comment or follow me on social media @coderstea on Twitter, Linkedin, Facebook, or Instagram. I will be happy to help you guys. So let’s just get started then, shall we? but before, prepare your cup of tea to sip and code.
Why Use partitioningBy Collector
Sometimes, you need to see if the element of the collection is fulfilling a certain condition. But, we don’t want to skip or remove the failed elements, instead, we just want to partition them into true and false buckets. In the Stream,
filter can be used to check if the object or element is passing the condition or not. However, it totally blocks objects which fails the condition. So you only get a true or false derived object in the next pipe depending on the condition, which we don’t want.
So our option is to do this via the imperative style of programming like using a map, a loop, and in the if statement populating that map (one of many solutions). What if you can do all these steps in a single statement? How reduced your code will be. And the side effect will be a much more readable, maintainable, and self-explanatory code, isn’t it?. That statement is partitioningBy. In its simplest form, just provide the condition, and thats it. It takes care of all the things and gives you Map of Boolean and the List i.e
Map<Boolean, List<T>>>. Now let’s see it HOW.
How to Use partitioningBy Collector
To use the
partitioningBy, you have to pass the
Collectors.partitioningBy in the
collect() method of Stream API. Like the following,
numberList.stream().collect(Collectors.partitioningBy(num -> num % 2 ==0));
groupingBy, discussed here,
partitioningBy is really simple. It mainly requires the Predicate as a parameter, and if you want to do some operation on the sublist then another param of Collector can be added.
// create a sublist partitioningBy(Predicate<T> predicate) // do operaton on the partition partitioningBy(Predicate<T> predicate, Collector<T, A, D> downstream)
Don’t worry we will take a look at them one by one with example.
Using partitioningBy Collector to Separate the List
Let’s talk about the first one i.e
partitioningBy(Predicate<T> predicate). Learn more about the Predicate here. As I said, using this Predicate you simply partition the list into true or false sublists. Here is some example, of how you can use it to separate the list based on some conditions.
Partition Even and Odd Numbers In Stream API
The following program would separate the odd and even numbers in the map with false and true keys respectively.
List<Integer> numberList = Arrays.asList(0,1,2,3,4,5,6,7,8,9); // partitionBy even numbers // true sublist will be even numbers and false will be odd numbers Map<Boolean, List<Integer>> evenNumberMap = numberList.stream() .collect(Collectors.partitioningBy(num -> num % 2 == 0)); System.out.println("The Even Numbers are" + evenNumberMap.get(true));
Separate the Numbers Greater and Less than n
Let’s say, now you want to separate the numbers if they are greater than or equal to 5. Here is how you can do it with partitioningBy.
// partitioningBy numbers greater than and less than 5 Map<Boolean, List<Integer>> gt5Map = numberList.stream() .collect(Collectors.partitioningBy(num -> num >= 5)); System.out.println("The Numbers Greater than or equal to 5 are" + gt5Map.get(true)); System.out.println("The Numbers Less than 5 are" + gt5Map.get(false));
And like this, you can play according to your requirements. Now let us see how to perform an action against the sublist.
Perform DownStream Operations on partitioningBy List
Now, you just don’t want to have the sublist but want to have a computed value in the map. Such as max value within the sublist or average, or some other Collector operation. The syntax for the downstream operation is as follows.
partitioningBy(Predicate<T> predicate, Collector<T, A, D> downstream)
Here are a few examples to get you started.
Get the Average using partitioningBy
I will use the same number list. Now instead of generating the odd or even sublist, I will compute the average of it in the Map. To do the average we will use the
Collectors.averagingInt and pass the value with
Integer::intValue to pass it as a
// partitioningBy odd and even with their average // partitioningBy odd and even with their average Map<Boolean, Double> oddEvenAverage = numberList.stream() .collect(Collectors.partitioningBy( num -> num % 2 != 0, Collectors.averagingInt(Integer::intValue) )); System.out.println("Odd numbers average is " + oddEvenAverage.get(true)); System.out.println("Even numbers average is " + oddEvenAverage.get(false));
partitioningBy to Get Set instead of List
Now you don’t want to have a List, rather a Set. Just pass the `
// partitioningBy odd even with Set Map<Boolean, Set<Integer>> oddEvenSet = numberList.stream() .collect(Collectors.partitioningBy( num -> num % 2 != 0, Collectors.toSet() ));
Nested partitioningBy Collector
I want to have numbers separated by if it is greater or equal to 5. After separation, I again want to separate the odd and even numbers. Here is how I will do it.
// partitioningBy greater or equal to 5 and then // partitioningBy even and odd Map<Boolean, Map<Boolean, List<Integer>>> gte5EvenOddMap = numberList.stream() .collect(Collectors.partitioningBy( num -> num >= 5, Collectors.partitioningBy( num -> num % 2 == 0 //again can add more partitioningBy... ) )); System.out.println("Odd numbers Greater than 5 are " + gte5EvenOddMap.get(true).get(false)); System.out.println("Even numbers Greater than 5 are " + gte5EvenOddMap.get(true).get(true)); System.out.println("Even numbers Less than 5 are " + gte5EvenOddMap.get(false).get(true));
With this 2nd parameter, downstream Collector, you can be so much creative according to your need. I can keep going with different examples but I think these are enough to understand the concept.
Thats it for this post. Hope you have understood how to use partitioningBy Collector in Stream API. The full code is available on GitHub. If you liked the post or if you have any queries about this, please let me know in the comment. You can follow me on social media @coderstea on Twitter, Linkedin, Facebook, or Instagram. You can also publish your own post on CodersTea.com, just share your thought on Contact Us.
See you in the next post. HAKUNA MATATA!!!