Partitioning in Java 8
-
Last Updated: June 10, 2024
-
By: javahandson
-
Series
In this article, we will understand what is Partitioning in Java 8. We will also learn about different variants of partitioning methods with examples.
Partitioning is a special case of grouping. Here we will use a predicate function to partition the elements of the Stream into 2 groups and store them in a map.
As we are using a predicate function for partitioning hence the resultant key of the map will be a boolean value therefore there can be at most two different groups one for true and one for false.
The Collectors class has given two overloaded partitioningBy methods that help to group the elements based on a predicate. If you are not aware of what a predicate is then you can refer to this article on predefined interfaces.
There are 2 variants of partitioningBy method present in the Collectors class.
static<T> Collector<T, ?, Map <Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)
a. static<T>: This indicates that partitioningBy is a static method. <T> is a generic type parameter where T is the type of the input elements.
b. Collector<T, ?, Map <Boolean, List<T>>>: The method returns a Collector that when applied to a stream of type T, will produce a Map where:
? indicates that the type of the intermediate result is unspecified and will be handled by the implementation
c. predicate: A Predicate that returns true or false for each element. This predicate determines how the elements will be partitioned.
Write a program to filter the even and odd numbers.
package com.javahands.collectors.partitioning; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class PartitioningEx { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10); Map<Boolean, List<Integer>> map = list.stream().collect(Collectors .partitioningBy(number -> number % 2 == 0)); System.out.println(map); } } Output: {false=[1, 3, 5, 7, 7, 9], true=[2, 2, 4, 6, 8, 10]}
In the above example, the predicate function is to filter the even numbers hence the resultant key for the even numbers is true whereas the remaining are odd numbers so the resultant key for the odd numbers is false.
If we write a predicate function to filter the odd numbers then the resultant key for the odd numbers will be true and the key for the even numbers will be false. Let’s check it below.
package com.javahands.collectors.partitioning; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class PartitioningEx { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10); Map<Boolean, List<Integer>> map = list.stream().collect(Collectors .partitioningBy(number -> number % 2 != 0)); System.out.println(map); } } Output: {false=[2, 2, 4, 6, 8, 10], true=[1, 3, 5, 7, 7, 9]}
static<T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector <? super T, A, D> downstream)
a. static<T, D, A>: This indicates that partitioningBy is a static method. <T, D, A> are generic type parameters where:
b. Collector<T, ?, Map>: The method returns a Collector. When this method is applied to a stream of type T it will produce a Map where:
? indicates that the type of the intermediate result is unspecified and will be handled at the time of implementation
c. predicate: A Predicate that returns true or false for each element. This predicate determines how the elements will be partitioned.
d. Collector<? super T, A, D> downstream: This downstream collector specifies how the partitioned elements will be collected further.
Write a program to filter the even and odd numbers and store the numbers in a Set (instead of a list)
Usually, if we are not giving any downstream collector then the numbers are getting stored in a list (Duplicate elements will be stored).
In the below program, we will explicitly specify the downstream collector so as to store the numbers in a set, so that duplicate elements will be ignored.
package com.javahands.collectors.partitioning; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; public class PartitioningEx { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10); Map<Boolean, Set<Integer>> map = list.stream().collect(Collectors .partitioningBy(number -> number % 2 == 0, Collectors.toSet())); System.out.println(map); } } Output: {false=[1, 3, 5, 7, 9], true=[2, 4, 6, 8, 10]}
Write a program to count the number of even and odd numbers in a list.
package com.javahands.collectors.partitioning; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.Predicate; import static java.util.stream.Collectors.counting; import static java.util.stream.Collectors.partitioningBy; public class PartitioningEx { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 10); Predicate<Integer> predicate = number -> number % 2 == 0; Map<Boolean, Long> map = list.stream().collect(partitioningBy(predicate, counting())); System.out.println("Count of even numbers : " + map.get(true)); System.out.println("Count of odd numbers : " + map.get(false)); } } Output: Count of even numbers : 5 Count of odd numbers : 4
We will go a step further and check how we can use SummaryStatistics as a downstream collector instead of just using a primitive type a List or a Set. This will give you a better understanding of partitioningBy method and how to use different downstream collectors.
To know more about summary statistics in Java 8 you can refer to this article summarizing methods
Write a program to partition the students in 2 groups based on whether their marks are greater than 400 or not. For each group, we want to gather statistics about their marks, such as the average marks, the maximum marks, and the count of students in each group.
package com.javahands.collectors.partitioning; public class Student { int rollNumber; String name; int marks; public Student(int rollNumber, String name, int marks) { this.rollNumber = rollNumber; this.name = name; this.marks = marks; } public int getMarks() { return marks; } }
package com.javahands.collectors.partitioning; import java.util.Arrays; import java.util.IntSummaryStatistics; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; public class PartitioningDemo { public static void main(String[] args) { List<Student> students = Arrays.asList( new Student(101, "Suraj", 450), new Student(102, "Iqbal", 470), new Student(103, "Amar", 330), new Student(104, "Amit", 400), new Student(105, "Suchit", 380), new Student(106, "Kartik", 290)); // Define a predicate to partition employees based on a salary threshold Predicate<Student> marksAbove400 = student -> student.getMarks() > 400; // Partition students based on the predicate and collect marks statistics for each group Map<Boolean, IntSummaryStatistics> salaryStatistics = students.stream() .collect(Collectors.partitioningBy( marksAbove400, Collectors.summarizingInt(Student::getMarks) )); // Print the results System.out.println("Marks statistics for students scored more than 400:"); System.out.println(salaryStatistics.get(true)); System.out.println("Marks statistics for students scored less than or equal to 400:"); System.out.println(salaryStatistics.get(false)); } } Output: Marks statistics for students scored more than 400: IntSummaryStatistics{count=2, sum=920, min=450, average=460.000000, max=470} Marks statistics for students scored less than or equal to 400: IntSummaryStatistics{count=4, sum=1400, min=290, average=350.000000, max=400}
So this is all about partitioning in Java 8. If you have any questions on this topic, please raise them in the comments section. If you liked this article then please share this post with your friends and colleagues.