A complete guide to groupingby concept in java 8 and how to perform the group by operations using java 8 collectors api with example programs.
1. Overview
In this tutorial, We will learn how to perform the groupingby operation in java 8.
If you have worked in Oracle database, you must have seen the group by operator in may complex sql queries.
In the similar way, we can implement the group by clause from java 8 onwards. Java 8 Stream api is added with the data grouping capabilities as part of Collectors api.
Collectors API is to collect the final data from stream operations.
2. Java 8 Collectors GroupingBy Syntax
groupingBy() method is an overloaded method with three methods.
This method returns a new Collector implementation with the given values.
public static <T,K> Collector<T,?,Map<K,List<T>>> groupingBy(Function<? super T,? extends K> classifier) public static <T,K,A,D> Collector<T,?,Map<K,D>> groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream) public static <T,K,D,A,M extends Map<K,D>> Collector<T,?,M> groupingBy(Function<? super T,? extends K> classifier, Supplier<M> mapFactory, Collector<? super T,A,D> downstream)
Note:
Remember always group by operations returns a Map with the actual key and aggregated result as value.
3. Java 8 GroupingBy - Group by count
First, let us understand the simple group by operation to find the number of occurrences of each string from List.
package com.javaprogramto.java8.collectors.groupby; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; public class GroupingByCount { public static void main(String[] args) { // Creating List and adding duplicate values. List<String> strings = new ArrayList<>(); strings.add("Hello"); strings.add("Ram"); strings.add("Hello"); strings.add("Sam"); strings.add("Hello"); strings.add("Yam"); strings.add("Hello"); strings.add("Raj"); strings.add("Hello"); strings.add("Raj"); // Grouping by based on the count Map<String, Long> countMap = strings.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); // printing the count of each string using groupingBy() System.out.println("Count : "+countMap); } }
Output:
Count : {Yam=1, Hello=5, Raj=2, Sam=1, Ram=1}
In the input list, word Hello is repeated 5 times, Raj is for 2 time and reaming are for 1 time.
Group by operation is simplified using new java 8 collectors api.
4. Java 8 - Grouping By and Sort
Next, Look at the another example to sort the count operation.
package com.javaprogramto.java8.collectors.groupby; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.function.Function; import java.util.stream.Collectors; public class GroupingByCountSort { public static void main(String[] args) { // Creating List and adding duplicate values. List<String> strings = new ArrayList<>(); strings.add("Hello"); strings.add("Ram"); strings.add("Hello"); strings.add("Sam"); strings.add("Hello"); strings.add("Yam"); strings.add("Hello"); strings.add("Raj"); strings.add("Hello"); strings.add("Raj"); // Grouping by based on the count Map<String, Long> countMap = strings.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); Map<String, Long> groupBySorted = countMap.entrySet().stream().sorted(Entry.comparingByValue()) .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (e1, e2) -> e2, LinkedHashMap::new)); // printing the count of each string and sorted System.out.println("Count sorted : " + groupBySorted); } }
Output:
Count sorted : {Yam=1, Sam=1, Ram=1, Raj=2, Hello=5}
Output map is sorted by value in ascending order.
5. Java 8 Group by Sort Descending Order
// Descending Order // Grouping by based on the count Map<String, Long> countMap2 = strings.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); Map<String, Long> finalMapDescendingOrder = new LinkedHashMap<>(); // Sort a map and add to finalMap countMap2.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()) .forEachOrdered(e -> finalMapDescendingOrder.put(e.getKey(), e.getValue())); System.out.println("Descending order sorted - " + finalMapDescendingOrder);
Output:
Descending order sorted - {Hello=5, Raj=2, Yam=1, Sam=1, Ram=1}
6. GroupingBy with List of Custom Objects
Let us create a custom class called Stock with name, quantity and price properties.
Create objects for Stock class and add to List.
Next, perform group by on stock name and sum quantity.
Stock.java
package com.javaprogramto.java8.collectors.groupby; public class Stock { private String name; private int quantity; private double price; public Stock(String name, int quantity) { this.name = name; this.quantity = quantity; } public Stock(String name, int quantity, double price) { super(); this.name = name; this.quantity = quantity; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getQuantity() { return quantity; } public void setQuantity(int quantity) { this.quantity = quantity; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } }
GroupingBy by Sum:
package com.javaprogramto.java8.collectors.groupby; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class GroupingByCountObjects { public static void main(String[] args) { // Creating List and adding duplicate values. List<Stock> stocks = new ArrayList<>(); stocks.add(new Stock("JP Morgan", 10)); stocks.add(new Stock("ICICI", 10)); stocks.add(new Stock("HDFC", 10)); stocks.add(new Stock("ICICI", 10)); stocks.add(new Stock("JP Morgan", 10)); stocks.add(new Stock("JP Morgan", 10)); // group by - stock name + sum(quanity) Map<String, Integer> noOfStocksByName = stocks.stream() .collect(Collectors.groupingBy(Stock::getName, Collectors.summingInt(Stock::getQuantity))); // printing the count of each string. System.out.println("No of stocks by stock name : " + noOfStocksByName); } }
Output:
No of stocks by stock name : {ICICI=20, HDFC=10, JP Morgan=30}
7. GroupingBy by Multiple Fields
Next, apply the group by on multiple fields of Stock Name and Quantity. If these two fields are equal then get the count for no of stock objects.
package com.javaprogramto.java8.collectors.groupby; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class GroupingByMultipleFields { public static void main(String[] args) { // Creating List and adding duplicate values. List<Stock> stocks = new ArrayList<>(); stocks.add(new Stock("JP Morgan", 10, 100)); stocks.add(new Stock("ICICI", 20, 100)); stocks.add(new Stock("HDFC", 30, 300)); stocks.add(new Stock("ICICI", 20, 200)); stocks.add(new Stock("JP Morgan", 10, 100)); stocks.add(new Stock("JP Morgan", 10, 100)); // group by - stock name + quanity Map<String, Map<Integer, Long>> noOfStocksByName = stocks.stream() .collect(Collectors.groupingBy(Stock::getName, Collectors.groupingBy(Stock::getQuantity, Collectors.counting()))); // printing the count of each string. System.out.println("Group by on multiple properties" + noOfStocksByName); } }
Output:
Group by on multiple properties{ICICI={20=2}, HDFC={30=1}, JP Morgan={10=3}}
8. Conclusion
In this article, We have seen how to use group by function in java 8 collections.
Examples shown to get the count, sort, sum on custom objects, group by on multiple fields.
And alos we can modify the return Map value type, Getting the average, sum, minimum, maximum and Summary values from grouped results.
COMMENTS