Overview of groupingBy in Java 8 Streams
The groupingBy collector in Java 8 is part of the Collectors class and is used to group elements in a stream by a specified classifier function. It works similarly to the SQL GROUP BY statement, where data is categorized based on certain attributes. The result is typically a Map, where the keys are the grouping criteria, and the values are the grouped elements.
Steps to Use groupingBy
Prepare Your Data: Have a Collection or Stream of elements (e.g., a List of objects).
Stream Your Data: Convert your collection into a stream using .stream().
Group Elements:
Use Collectors.groupingBy() to specify how the elements should be grouped.
Optionally, apply downstream collectors for further aggregation (e.g., counting(), mapping()).
Examples 1 : Group by String length
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GroupingByExample {
public static void main(String[] args) {
// Sample data
List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");
// Group words by their length
Map<Integer, List<String>> groupedByLength = words.stream()
.collect(Collectors.groupingBy(String::length));
// Output the result
System.out.println("Grouped by Length: " + groupedByLength);
}
}
Output:
Grouped by Length: {3=[fig], 4=[date], 5=[apple, grape], 6=[banana, cherry]}
Explanation:
String::length is the classifier function that groups the words by their length.
The result is a Map where the key is the word length, and the value is a list of words with that length.
Exmaple 2: Group employee by department
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Employee {
String name;
String department;
Employee(String name, String department) {
this.name = name;
this.department = department;
}
@Override
public String toString() {
return name;
}
}
public class GroupingByExample {
public static void main(String[] args) {
// Sample data
List<Employee> employees = Arrays.asList(
new Employee("Alice", "HR"),
new Employee("Bob", "IT"),
new Employee("Charlie", "HR"),
new Employee("David", "Finance"),
new Employee("Eve", "IT")
);
// Group employees by department
Map<String, List<Employee>> groupedByDepartment = employees.stream()
.collect(Collectors.groupingBy(employee -> employee.department));
// Output the result
System.out.println("Grouped by Department: " + groupedByDepartment);
}
}
output:
Grouped by Department: {Finance=[David], HR=[Alice, Charlie], IT=[Bob, Eve]}
Explanation:
The classifier function is employee -> employee.department, which groups employees by their department.
The result is a Map where the key is the department, and the value is a list of employees in that department.
Example 3: Group and Count Elements
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GroupingByCounting {
public static void main(String[] args) {
// Sample data
List<String> items = Arrays.asList("apple", "banana", "apple", "orange", "banana", "apple");
// Group and count occurrences
Map<String, Long> itemCounts = items.stream()
.collect(Collectors.groupingBy(item -> item, Collectors.counting()));
// Output the result
System.out.println("Item Counts: " + itemCounts);
}
}
Output:
Item Counts: {orange=1, banana=2, apple=3}
Explanation:
The classifier function is item -> item, grouping elements by their value.
The downstream collector Collectors.counting() counts the occurrences of each group.
Key Features of groupingBy
Basic Grouping:
Groups elements based on a key or classifier.
E.g., Collectors.groupingBy(Function.identity()).
Downstream Collectors:
Apply further operations like counting, mapping, or reducing on the grouped elements.
Example: Collectors.groupingBy(key, Collectors.counting()).
Nested Grouping:
Group by multiple levels using nested groupingBy.
Example: Group employees by department and then by job title.
Custom Map Implementation:
Use the three-argument version of groupingBy to specify the type of Map to use for the result.
Nested grouping with groupingBy in Java 8 allows you to group elements by multiple levels. This involves creating a Map where each key corresponds to a group, and the value is another map representing the next level of grouping. Here’s how to achieve this with some examples:
Example 1: Group Employees by Department and then by Designation
java
Pimport java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Employee {
String name;
String department;
String designation;
Employee(String name, String department, String designation) {
this.name = name;
this.department = department;
this.designation = designation;
}
@Override
public String toString() {
return name;
}
}
public class NestedGroupingExample {
public static void main(String[] args) {
// Sample data
List<Employee> employees = Arrays.asList(
new Employee("Alice", "HR", "Manager"),
new Employee("Bob", "IT", "Developer"),
new Employee("Charlie", "HR", "Executive"),
new Employee("David", "IT", "Developer"),
new Employee("Eve", "Finance", "Analyst")
);
// Nested grouping by department and then by designation
Map<String, Map<String, List<Employee>>> groupedByDeptAndDesignation = employees.stream()
.collect(Collectors.groupingBy(
emp -> emp.department, // First level grouping: by department
Collectors.groupingBy(
emp -> emp.designation // Second level grouping: by designation
)
));
// Print the result
System.out.println("Grouped by Department and Designation: " + groupedByDeptAndDesignation);
}
}
Output:
Grouped by Department and Designation: {
HR={Manager=[Alice], Executive=[Charlie]},
IT={Developer=[Bob, David]},
Finance={Analyst=[Eve]}
}
Explanation:
The first groupingBy groups employees by their department.
The second groupingBy further groups employees by their designation within each department.
The result is a nested Map<String, Map<String, List<Employee>>>.
Example 2: Group Words by Length and then by Their Initial Character
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class NestedGroupingWords {
public static void main(String[] args) {
// Sample data
List<String> words = Arrays.asList("apple", "ant", "banana", "cherry", "cat", "dog", "dragonfruit");
// Nested grouping by word length and then by the first character
Map<Integer, Map<Character, List<String>>> groupedByLengthAndFirstChar = words.stream()
.collect(Collectors.groupingBy(
String::length, // First level grouping: by length of the word
Collectors.groupingBy(
word -> word.charAt(0) // Second level grouping: by the first character
)
));
// Print the result
System.out.println("Grouped by Length and First Character: " + groupedByLengthAndFirstChar);
}
}
Output:
Grouped by Length and First Character: {
3={a=[ant], c=[cat], d=[dog]},
5={a=[apple]},
6={b=[banana]},
7={c=[cherry]},
11={d=[dragonfruit]}
}
Explanation:
The first groupingBy groups words by their length.
The second groupingBy groups words within each length group by their first character.
No comments:
Post a Comment