Java 8 Collectors.groupingBy() Method Example
In this blog post, we will explore the Collectors.groupingBy()
method, a valuable tool for grouping elements in a stream based on specific criteria. We will explore its syntax, and usage, and provide illustrative examples to demonstrate its capabilities.
The Collectors.groupingBy()
method is part of the java.util.stream
package, introduced in Java 8, and facilitates the grouping of elements in a stream based on a provided classification function. The elements of the stream are divided into different groups, where each group is represented by a unique key.
Syntax:
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
Function<? super T, ? extends K> classifier)
Key Components:
- T: The type of input elements in the stream.
- K: The type of keys used to represent groups.
- classifier: A function that extracts the grouping key from each element.
1. Grouping a List of Strings by Their Length
Let’s start with a simple example to group a list of strings based on their lengths.
package org.websparrow;
import java.util.*;
import java.util.stream.Collectors;
public class GroupingByExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple", "banana", "orange", "kiwi", "grape");
Map<Integer, List<String>> groupedFruits = fruits.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(groupedFruits);
}
}
Output:
{5=[apple, grape], 6=[banana, orange], 4=[kiwi]}
In this example, we used the Collectors.groupingBy()
method to group the fruits based on their string lengths. As a result, we obtained a Map where the keys represent the length of the strings and the corresponding values are lists of strings with the same length.
2. Grouping a List of Objects by Their Attributes
The Collectors.groupingBy()
method is not limited to grouping strings; it can be used with custom objects as well. Let’s demonstrate this with an example:
Suppose we have a class named Person
with attributes name
and age
.
package org.websparrow;
import java.util.*;
import java.util.stream.Collectors;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class GroupingByCustomObjectsExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 30),
new Person("David", 25)
);
Map<Integer, List<Person>> groupedPeopleByAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
System.out.println(groupedPeopleByAge);
}
}
Output:
{25=[Person{name='Bob', age=25}, Person{name='David', age=25}], 30=[Person{name='Alice', age=30}, Person{name='Charlie', age=30}]}
In this example, we grouped the list of Person
objects based on their ages. The groupedPeopleByAge
map contains the age as keys and lists of Person
objects with the same age as values.
Is Collectors.groupingBy() overloaded method?
Yes, the Collectors.groupingBy()
method is overloaded. It provides multiple variations to cater to different grouping requirements. Here are the two main overloaded versions of the Collectors.groupingBy()
method:
1. Grouping by a single classification function:
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
2. Grouping by a single classification function with a downstream collector:
public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream)
Explanation of Parameters:
- T: The type of the input elements in the stream.
- K: The type of the keys used to represent groups.
- A: The intermediate accumulation type of the downstream collector (used for optimization).
- D: The final result type of the downstream collector.
The second overloaded version is more versatile as it allows you to apply another collector on the grouped elements, thus enabling more complex aggregations or transformations on the grouped data.
Example of the second overloaded version:
package org.websparrow;
import java.util.*;
import java.util.stream.Collectors;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class GroupingByWithDownstreamExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 30),
new Person("David", 25)
);
// Grouping by age and counting the number of people in each group
Map<Integer, Long> groupedPeopleByAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
System.out.println(groupedPeopleByAge);
}
}
Output:
{25=2, 30=2}
In this example, we used the second overloaded version of Collectors.groupingBy()
to group the Person
objects based on their age and also count the number of people in each age group using the Collectors.counting()
downstream collector. The resulting map contains the age as keys and the count of people with that age as values.
Conclusion
The Collectors.groupingBy()
method is a valuable addition to Java’s stream library, offering an efficient and concise way to group elements based on specific attributes or criteria. By leveraging the power of streams and collectors, Java developers can easily perform data transformations and aggregations, making their code more expressive and maintainable.
References
- Java 8- Find the nth Highest Salary
- Find nth Largest elements from Integer List using Java Stream
- groupingBy() – JavaDoc