

Table of Contents
Overview
Implementations of Collector
that implement various useful reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc. Here is different ways of java 8 stream group by count with examples like grouping, counting, filtering, summing, averaging, multi-level grouping.
Example 1: Grouping by + Counting
Collectors class provide static factory method groupingBy
which provides a similar kind of functionality as SQL group by clause.
Another useful static method is counting
which returns a collector accepting an element of T that count number of input elements.
Let’s say we want to group all the elements in a list and count each element occurrences. till Java 7 it was such a lengthy task. Java 8 brings some new capabilities with lambda expression and improved collections API to reduce developer time. Now with Java 8 we can group element of an arraylist and count it’s occurences in just one line of code.
package com.javadeveloperzone; import java.util.Arrays; import java.util.stream.Collectors; /** * Created by Lenovo on 30-04-2017. */ public class GroupingByCountExample { public static void main(String... args) { java.util.List<String> strings = Arrays.asList("Zohne", "Redy", "Zohne", "Redy", "Stome"); java.util.Map<String, Long> nameCount = strings.stream().collect(Collectors.groupingBy(string -> string, Collectors.counting())); nameCount.forEach((name, count) -> { System.out.println(name + ":" + count); }); } }
Output
As you can see in below output Zohne and redy comes two times in the list and Stome comes once. We can also compare these names with case insensitivities, remove any punctuation marks etc…
Zohne:2 Stome:1 Redy:2
Example: Grouping by + Counting + Filtering
Let’s think of one step ahead, We always use SQL group by clause with HAVING
clause.
Here we have used collectionAndThen
static method which takes two arguments. First one is Collector
and second one is finisher function.
In below example, we will take only those values whose grouping by count greater than 2. So first we will do grouping and than perform filter on result map and then return values. Equivalent SQL server query to this code looks like “SELECT empName from employee groupBy empName having count(empName)>1”
java.util.Set<String> grupingThanFilter = allWords.stream().collect(Collectors.collectingAndThen(Collectors .groupingBy(Function.identity(), Collectors.counting()),map->{ map.values().removeIf(l -> l<=2); return map.keySet(); })); grupingThanFilter.forEach(System.out::println);
Output:
Here as you can see elements which have only one occurrence is removed.
Zohne Redy
Example 3: Grouping by + summingInt
Let’s say we want to group by the employee by it’s designation and calculate total salary based on the designation.
Collectors class provide another usefull static method summingInt
which a collector that produces the sum of an integer value function.
In below example, we have used groupingBy
on employee Designation and apply summingInt on employee salary.
java.util.List<Employee> employees = Employee.getEmployee(); java.util.Map<String, Integer> designationWiseTotalSalary = employees.stream().collect(Collectors .groupingBy(Employee::getDesignation, Collectors.summingInt(Employee::getSalary))); designationWiseTotalSalary.forEach((k, v) -> { System.out.println(k + " : " + v); });
Output:
Sr. Developer : 72000 Developer : 113000 CEO : 100000
Example 4: Grouping by + averagingLong
As we discussed earlier, summingInt use to calculate total/sum of an integer, similar way another method called averagingLong
and averagingInt
is used to calculate average.
Let’s say we want to find the average salary of all the designation of employees using the new Java Collection and lambda API. We can use groupingBy and averagingLong/averagingInt method to achieve the same. Refer below code snippets for more details.
java.util.List<Employee> employees = Employee.getEmployee(); java.util.Map<String, Double> designationWiseEvgSalary = employees.stream().collect(Collectors .groupingBy(Employee::getDesignation, Collectors.averagingLong(Employee::getSalary))); designationWiseEvgSalary.forEach((k, v) -> { System.out.println(k + " : " + v); });
Output:
Sr. Developer : 72000.0 Developer : 28250.0 CEO : 100000.0
Example 5: Multi Level Grouping by + averagingInt
Let’s say we want to find the average salary of all the male and female employee based on his/her designation.
In this type of use cases, we need to group employee first by it’s designation and then group by on gender to achieve multi level grouping by
.
Refer below code snippets for more details.
java.util.List<Employee> employees = Employee.getEmployee(); java.util.Map<String, java.util.Map<String, Double>> designationGroupByAvg = employees.stream() .collect(Collectors .groupingBy(Employee::getDesignation, Collectors .groupingBy(Employee::getGender, Collectors .averagingInt(Employee::getSalary)))); designationGroupByAvg.forEach((designation, values) -> { System.out.println("Designation:" + designation); values.forEach((gender, avg) -> { System.out.println(gender + ":" + avg); }); System.out.println(); });
Output:
As you can see in below output average salary of all the male and female employee along with his/her designation.
Designation:Sr. Developer Male:72000.0 Designation:Developer Female:24000.0 Male:32500.0 Designation:CEO Male:100000.0
Employee.java
package com.javadeveloperzone; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; /** * Created by JavaDeveloperZone on 29-04-2017. */ public class Employee { private int no; private String name; private String designation; private String gender; private int salary; private java.util.Set<String> language = new HashSet<String>(); public Employee(int no, String name, String designation, String gender,int salary) { this.no = no; this.name = name; this.designation = designation; this.gender = gender; this.salary = salary; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesignation() { return designation; } public void setDesignation(String designation) { this.designation = designation; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } @Override public String toString() { return this.no + " : " + this.name + " : " + gender + " : " + designation; } public String addLanguage(String language) { this.language.add(language); return language; } public Set<String> getLanguage() { return language; } public static java.util.List<Employee> getEmployee() { java.util.List<Employee> employees = new ArrayList<>(); employees.add(new Employee(1, "Bob", "Developer", "Male",30000)); employees.add(new Employee(2, "Joy", "Sr. Developer", "Male",72000)); employees.add(new Employee(3, "John", "CEO", "Male",100000)); employees.add(new Employee(4, "Bat", "Developer", "Male",35000)); employees.add(new Employee(5, "Jolly", "Developer", "Female",36000)); employees.add(new Employee(6, "Bobby", "Developer", "Female",12000)); return employees; } }
References
- https://stackoverflow.com/questions/30515792/collect-stream-with-grouping-counting-and-filtering-operations
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html