Java 8 Collectors API Tutorial With Real Time Examples
A quick practical guide to Java 8’s Collectors api. Example programs on various useful reduction operations and accumulating elements into collections
1. Overview
In this tutorial, We’ll be learning to Java 8 Collectors API in-depth with all methods and example programs. Collectors is a public final class that extends Object class.
Read this article completely with patience. You will definitely become a master in Java 8’s Collectors by end of this post.
Collectors class provides various useful reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc
This has many methods that are very useful when working with Stream api.
Few methods: toList(), toMap(), toCollection(), joining(), summingInt(), groupingBy() and partitioningBy(), etc.
We will see the example programs on the below Collectors methods and how to use them.
Collectors API Methods:
- collect()
- toList()
- toSet()
- toUnmodifiableSet()
- toUnmodifiableList(()
- toCollection()
- toMap()
- toUnmodifiableMap()
- summingInt()
- averagingInt() / averagingLong() / averagingDouble()s
- counting()
- joining()
- groupingBy()
- partitioningBy()
- toConcurrentMap()
- filtering()
- flatMapping()
- maxBy()
- minBy()
- reducing()
- summarizingDouble() / summarizingInt() / summarizingLong()
- teeing()
Note: All methods in the Collectors class are static. So it is good to use static import.
If you are using many methods then use static import.
1 | import static java.util.stream.Collectors.*; |
If you are using only a few then use like this.
1 2 3 | import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.joining; |
We will be using the below Employee class in this article.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | class Employee { private int id; private String name; private int age; private String region; private double sal; public Employee( int id, String name, int age, String region, double sal) { this .id = id; this .name = name; this .age = age; this .region = region; this .sal = sal; } // Standard setters and getters } |
Creating an Employee List.
1 2 3 4 5 | List<Employee> employeeList = new ArrayList<>(); employeeList.add( new Employee( 100 , "Sundar" , 47 , "North America" , 450000 )); employeeList.add( new Employee( 200 , "Pichai" , 25 , "North America" , 50000 )); employeeList.add( new Employee( 300 , "Larry" , 30 , "Asia" , 450000 )); employeeList.add( new Employee( 400 , "Page" , 59 , "Africa" , 450000 )); |
2. Java 8 Stream.collect() Example
Java 8’s most powerful stream method is collect() method. Which is also called a Terminal method. This is part of Stream API.
It allows us to perform mutable fold operations (repackaging elements to some data structures and applying some additional logic, concatenating them, etc.) on data elements held in a Stream instance.
The strategy for this operation is provided via Collector interface implementation.
3. Collectors.toList() Example
toList() collector can be used for collecting all Stream elements into a List instance.
Example to collect all employee names into List using toList() method.
1 2 | List<String> namesList = employeeList.stream().map(e -> e.getName()).collect(Collectors.toList()); System.out.println(namesList); |
Output:
1 | [Sundar, Pichai, Larry, Page] |
But, there are no guarantees on the type, mutability, serializability, or thread-safety of the List returned.
If you need more control over what type of List should be returned then should use toCollection(Supplier) method.
4. Collectors.toSet() Example
toSet() collector is used for collecting all Stream elements into a Set instance.
Example to collect all the regions into Set.
1 2 | Set<String> regionSet = employeeList.stream().map(e -> e.getRegion()).collect(Collectors.toSet()); System.out.println(regionSet); |
Output:
1 | [Asia, Africa, North America] |
But, there are no guarantees on the type, mutability, serializability, or thread-safety of the Set returned.
If you need more control over what type of Set should be returned then should use the toCollection(Supplier) method.
5. Collectors.toUnmodifiableSet() Example
This collects the elements into an unmodifiable set.
The set is created using the toSet() method can be modified.
1 2 | regionSet.add( "hello" ); System.out.println(regionSet); |
Output:
1 | [Asia, Africa, hello, North America] |
toUnmodifiableSet() method works similar to the toSet() but this set can not be modified.
1 2 | Set<Double> unmodifiableSet = employeeList.stream().map(e -> e.getSal()).collect(Collectors.toUnmodifiableSet()); System.out.println(unmodifiableSet); |
Output:
1 | [ 450000.0 , 50000.0 ] |
If we try to modify set then will throw UnsupportedOperationException.
1 | unmodifiableSet.add(10983d); |
Exception:
1 2 | Exception in thread "main" java.lang.UnsupportedOperationException at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java: 72 ) |
The returned collector does not allow null values. This will throw NullPointerException if it is presented with a null value.
1 2 | employeeList.add( null ); Set<Employee> empSet = employeeList.stream().collect(Collectors.toUnmodifiableSet()); |
The above code will cause NullPointerException. The same will be in the case of the toSet() method.
6. Collectors.toUnmodifiableList(() Example
This is similar to the toList() but toUnmodifiableList will collect elements into an unmodifiable List.
1 2 | List<Double> unmodifiableList = employeeList.stream().map(e -> e.getSal()).collect(Collectors.toUnmodifiableList()); System.out.println(unmodifiableList); |
Output:
1 | [ 450000.0 , 50000.0 , 450000.0 , 450000.0 ] |
This list holds duplicates, unlike Set.
If List has null value then it will throw java.lang.NullPointerException like toUnmodifiableSet.
7. Collectors.toCollection() Example
As you probably already noticed, when using toSet() and toList() collectors, you can’t make any assumptions of their implementations.
If you want to use a custom implementation or LinkedList or TreeSet, you will need to use the toCollection collector with a provided collection of your choice.
Example to collect the names into LinkedList as opposed to default List implementation.
1 2 | List<String> namesLinkedList = employeeList.stream().map(e -> e.getName()).collect(Collectors.toCollection(LinkedList:: new )); System.out.println(namesLinkedList); |
Output:
1 | [Sundar, Pichai, Larry, Page] |
Another example to collect regions into TreeSet.
1 2 | Set<String> regionTreeSet = employeeList.stream().map(e -> e.getRegion()).collect(Collectors.toCollection(TreeSet:: new )); System.out.println(regionTreeSet); |
Output:
1 | [Africa, Asia, North America] |
See the output is sorted because TreeSet sorts the values in it.
Note: This method does not work with immutable objects. In such type of cases, We must write custom Collector implementation or Use collectingAndThen().
8. Collectors.toMap() Example
toMap() Syntax:
1 | public static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper) |
Using toMap() method, A stream can be converted into a Map. But, this method needs two parameters.
keyMapper
valueMapper
These two are implementations of Function Functional Interface.
Functional Interface Function has a functional method R apply(T t) that accepts one argument and produces a result.
keyMapper will be used for extracting a Map key from a Stream element, and valueMapper will be used for extracting a value associated with a given key.
Now, We will create a map from a stream such that the map key is emp id and value is corresponding employee object.
1 | keyMapper = (e) -> e.getId() |
e refers to the Employee object and getting its id by calling getId() method.
1 | valueMapper = Function.identity() |
This method returns a function that always returns its input argument.
Function.identity() method does take one object as an argument and returns the same object with no change.
1 2 | Map<Integer, Employee> empMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity())); System.out.println(empMap); |
Output:
1 | { 400 =Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ], 100 =Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], 200 =Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], 300 =Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]} |
What happens if employeeList has duplicate employees with the same employee id.
Now adding a duplicate emp object with the same emp id but the different name “Larry Page”.
1 | employeeList.add( new Employee( 400 , "Larry Page" , 59 , "Africa" , 450000 )); |
Added a new emp object with emp id = 400.
1 | Map<Integer, Employee> empDupMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity())); |
Will throw the Runtime Exception as follow.
01 02 03 04 05 06 07 08 09 10 11 | Exception in thread "main" java.lang.IllegalStateException: Duplicate key 400 (attempted merging values Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ] and Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]) at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java: 133 ) at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$ 1 (Collectors.java: 180 ) at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java: 169 ) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java: 1654 ) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java: 484 ) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java: 474 ) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java: 913 ) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java: 234 ) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java: 578 ) at com.java.w3schools.blog.java8.streams.Java8CollectorExamples.main(Java8CollectorExamples.java: 76 ) |
Note: Map does not check the duplicate objects but does not allow duplicate keys.
toMap() function takes 3rd argument as BinaryOperator Functional Interface which has a functional method R apply(T t, U u). This functional method takes two arguments. In our case, the first argument takes the original employee, Second argument takes the duplicate employee and returns the employee object.
1 2 | Map<Integer, Employee> empDupMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp)); System.out.println(empDupMap); |
Output:
Here BinaryOperator will be invoked when there the same key appears. And returning duplicate objects from BinaryOperator apply() method. That replaces the old employee with a new duplicate employee. See the below output.
1 | { 400 =Employee [id= 400 , name=Larry Page, age= 59 , region=Africa, sal= 450000.0 ], 100 =Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], 200 =Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], 300 =Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]} |
Observe the employee with id 400 has a new name “Larry Page”. If we want to keep existing emp in the map and ignore the duplicate emp then we should return emp instead of sameEmp.
9. Collectors.toUnmodifiableMap() Example
Syntax:
1 2 | public static <T,K,U> Collector<T,?,Map<K,U>> toUnmodifiableMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper) public static <T,K,U> Collector<T,?,Map<K,U>> toUnmodifiableMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction) |
Returns a Collector that accumulates the input elements into an unmodifiable Map, whose keys and values are the result of applying the provided mapping functions to the input elements.
1 2 | Map<Integer, Employee> empUnmodifiedMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp)); System.out.println(empUnmodifiedMap); |
This function will throw NullPointerException if the keyMapper, valueMapper, or mergeFunction is null.
10. Collectors.summingInt() Example
summingInt() Method does the summation of all extracted elements from the stream and returns Integer.
Syntax:
1 | public static <T> Collector<T,?,Integer> summingInt(ToIntFunction<? super T> mapper) |
Example:
Finding the sum of all emp id’s using summingInt() method.
1 2 | int sumOfEmpIds = employeeList.stream().collect(Collectors.summingInt((Employee e) -> e.getId())); System.out.println( "Collectors.summingInt : " + sumOfEmpIds); |
Output:
1 | Collectors.summingInt : 1000 |
This method is to sum of int values.
Similar to this, Collector api has methods for summingLong(), summingDouble().
1 2 3 4 | public static <T> Collector<T,?,Long> summingLong(ToLongFunction<? super T> mapper) public static <T> Collector<T,?,Double> summingDouble(ToDoubleFunction<? super T> mapper) summingDouble() Example: |
Now, let us see the code to get the sum of salaries of all employees.
1 2 | double sumOfEmpSalss = employeeList.stream().collect(Collectors.summingDouble((Employee e) -> e.getSal())); System.out.println( "Collectors.summingDouble : " + sumOfEmpSalss); |
Output:
Collectors.summingDouble : 1400000.0
11. Collectors.averagingInt() / averagingLong() / averagingDouble() Examples
Collectors api has methods to get the average for integer, Long and Double values. These methods become now very handy to perform avg operations.
Internally arithmetic logic is applied for stream elements.
Syntax:
1 2 3 | public static <T> Collector<T,?,Double> averagingInt(ToIntFunction<? super T> mapper) public static <T> Collector<T,?,Double> averagingLong(ToLongFunction<? super T> mapper) public static <T> Collector<T,?,Double> averagingDouble(ToDoubleFunction<? super T> mapper) |
Here all these versions of methods return Double rather that its names describe.
Examples:
1 2 | double avgOfEmpSalss = employeeList.stream().collect(Collectors.averagingDouble((Employee e) -> e.getSal())); System.out.println( "Collectors.averagingDouble avg sal: " + avgOfEmpSalss); |
Output:
1 | Collectors.averagingDouble avg sal: 350000.0 |
12. Collectors.counting() Example
Syntax:
1 | public static <T> Collector<T,?,Long> counting() |
This method returns a Long value and just counts the values present in the Stream.
1 2 | long count = employeeList.stream().collect(Collectors.counting()); System.out.println( "Collectors.counting() : Count : " + count); |
Output:
1 | Collectors.counting() : Count : 4 |
13. Collectors.joining() Example
Syntax:
1 2 3 | public static Collector<CharSequence,?,String> joining() public static Collector<CharSequence,?,String> joining(CharSequence delimiter) public static Collector<CharSequence,?,String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) |
Joining() method does append the all contents of Stream the order they appear.
This is mainly designed for Strings with Stream<String>.
All versions of joining() methods return String.
joining() Example:
1 2 | String joinedStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining()); System.out.println( "joinedStr by using joining() method : " +joinedStr); |
Output:
1 | joinedStr by using joining() method : SundarPichaiLarryPage |
This joining() method just concatenates without adding any delimiter.
joining(CharSequence delimiter) Example:
If we want to add some delimiter then we should use this variant of the method.
1 2 | String joinedDelimiterStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining( " * " )); System.out.println( "joinedDelimiterStr by using joining(Delimiter) method : " +joinedDelimiterStr); |
Output:
1 | joinedDelimiterStr by using joining(Delimiter) method : Sundar * Pichai * Larry * Page |
Now observe the output that added * delimiter for each name.
joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) Example:
Example code to add some value to before and after delimiter is applied.
prefix will be added at the beginning after concatenating the delimiter to all values.
suffix will be added at the end after concatenating the delimiter to all values.
1 2 | String joinePrePostStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining( "*" , "@" , "|" )); System.out.println( "joinePrePostStr by using joining(Delimiter) method : " +joinePrePostStr); |
Output:
1 | joinePrePostStr by using joining(Delimiter) method : @Sundar *Pichai*Larry*Page| |
14. Collectors.groupingBy() Example
This groupingBy function works similar to the Oracle GROUP BY clause.
GroupingBy collector is used for grouping objects by some property and storing results in a Map instance.
We will see the example of the group by an employee region.
1 2 | Map<String, List<Employee>> groupByRegion = employeeList.stream().collect(Collectors.groupingBy((Employee e) -> e.getRegion())); System.out.println( "groupByRegion :: " +groupByRegion); |
Output:
1 | groupByRegion :: {Asia=[Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]], Africa=[Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]], North America=[Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ]]} |
The below two employees are stored under the “North America” region.
1 | Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ] |
By default, Map values are stored in the List.
If we want to make value is set then we should specify to the groupingBy() method as below.
1 | Map<String, Set<Employee>> groupByRegionSet = employeeList.stream().collect(Collectors.groupingBy((Employee e) -> e.getRegion(), Collectors.toSet())); |
15. Collectors.partitioningBy() Example
Syntax:
1 | public static <T> Collector<T,?,Map<Boolean,List<T>>> partitioningBy(Predicate<? super T> predicate) |
First, Take a look at the syntax.
From syntax, This method returns a Map and Boolean is key, List<T> as value. The returned Map always contains mappings for both false and true keys only.
1 2 | Map<Boolean, List<Employee>> partitionByAge = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30 )); System.out.println( "partitionByAge :: " +partitionByAge); |
partitioningBy() method takes Predicate Functional Interface which returns Boolean. Because of this, Key is always determined as Boolean and value is Employee object.
Output:
1 | partitionByAge :: { false =[Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]], true =[Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]]} |
Returned Map value is always a List. If you want to change it to another collection then we must use the below variant of groupingBy() method.
public static <T,D,A> Collector<T,?,Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector< super T,A,D> downstream)
Examples:
1 2 3 4 5 6 7 8 | // Set as Map value Map<Boolean, Set<Employee>> partitionByAgeSet = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30 , Collectors.toSet())); // LinkedList as Map value Map<Boolean, LinkedList<Employee>> partitionByAgeLinedList = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30 , Collectors.toCollection(LinkedList:: new ))); // TreeSet as Map value Map<Boolean, TreeSet<Employee>> partitionByAgeTreeSet = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30 , Collectors.toCollection(TreeSet:: new ))); |
To make working for TreeSort, the Employee class must implement
Comparable interface. Otherwise, will throw ClassCastException.
Note: If a partition has no elements, its value in the resulting Map will be an empty List.
16. Collectors.toConcurrentMap() Example
We have seen already toMap() in this post. If we want to store the result in Concurrent Map then we should use the toConcurrentMap() method.
Syntax:
1 2 3 | public static <T,K,U> Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper) public static <T,K,U> Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction) public static <T,K,U,M extends ConcurrentMap<K,U>> Collector<T,?,M> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapFactory) |
Examples:
1 | Map<Integer, Employee> empConcurrentMap = employeeList.stream().collect(Collectors.toConcurrentMap((e) -> e.getId(), Function.identity())); |
17. Collectors.filtering() Example
Stream api already has a filter() function. But, this is a very convenient way to do at a single place doing condition and collecting into List or Set.
Based on developer choice, We can choose Collectors or Stream api. Mostly, All use stream api filter() method.
Syntax:
1 | public static <T,A,R> Collector<T,?,R> filtering(Predicate<? super T> predicate, Collector<? super T,A,R> downstream) |
Examples:
For all stream elements, the first Predicate will be executed first and next downstream will be applied.
1 2 | List<Employee> filteredEmpList = employeeList.stream().collect(Collectors.filtering((Employee e) -> e.getAge() > 30 , Collectors.toList())); System.out.println( "Collectors.filtering() - filteredEmpList : " + filteredEmpList); |
Output:
1 | Collectors.filtering() - filteredEmpList : [Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]] |
18. Collectors.flatMapping() Example
This is very useful to convert a Collection of Collections into a flat map. The
flatMapping() collectors are most useful when used in a multi-level reduction, such as downstream of a groupingBy or partitioningBy.
Syntax:
1 | public static <T,U,A,R> Collector<T,?,R> flatMapping(Function<? super T,? extends Stream<? extends U>> mapper, Collector<? super U,A,R> downstream) |
Example:
Creating LineItem class.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | class LineItem { private int itemId; private String itemName; private Date manfacturedDate; public LineItem( int itemId, String itemName, Date manfacturedDate) { super (); this .itemId = itemId; this .itemName = itemName; this .manfacturedDate = manfacturedDate; } public int getItemId() { return itemId; } public void setItemId( int itemId) { this .itemId = itemId; } public String getItemName() { return itemName; } public void setItemName(String itemName) { this .itemName = itemName; } public Date getManfacturedDate() { return manfacturedDate; } public void setManfacturedDate(Date manfacturedDate) { this .manfacturedDate = manfacturedDate; } @Override public String toString() { return "LineItem [itemId=" + itemId + ", itemName=" + itemName + ", manfacturedDate=" + manfacturedDate + "]" ; } } |
Creating Customer class which has HAS-A relationship to LineIteam with List.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | class Customer { private int id; private String name; private boolean active; private String gender; private List<LineItem> lineItems; public Customer( int id, String name, boolean active, String gender, List<LineItem> lineItems) { super (); this .id = id; this .name = name; this .active = active; this .gender = gender; this .lineItems = lineItems; } public int getId() { return id; } public void setId( int id) { this .id = id; } public String getName() { return name; } public void setName(String name) { this .name = name; } public boolean isActive() { return active; } public void setActive( boolean active) { this .active = active; } public String getGender() { return gender; } public void setGender(String gender) { this .gender = gender; } public List<LineItem> getLineItems() { return lineItems; } public void setLineItems(List<LineItem> lineItems) { this .lineItems = lineItems; } } |
Creating Customer object 1
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | LineItem lineItem1 = new LineItem( 1001 , "Item 1" , new Date( 2010 , 07 , 01 )); LineItem lineItem2 = new LineItem( 1002 , "Item 2" , new Date( 2020 , 07 , 01 )); LineItem lineItem3 = new LineItem( 1003 , "Item 3" , new Date( 2030 , 07 , 01 )); LineItem lineItem4 = new LineItem( 1004 , "Item 4" , new Date( 2040 , 07 , 01 )); LineItem lineItem5 = new LineItem( 1005 , "Item 5" , new Date( 2050 , 07 , 01 )); List<LineItem> lineItemsList1 = new ArrayList<>(); lineItemsList1.add(lineItem1); lineItemsList1.add(lineItem2); lineItemsList1.add(lineItem3); lineItemsList1.add(lineItem4); lineItemsList1.add(lineItem5); Customer customer1 = new Customer( 100 , "Customer 1" , true , "M" , lineItemsList1); |
Creating Customer object 2
1 2 3 4 5 6 7 8 | LineItem lineItem6 = new LineItem( 2001 , "Item 6" , new Date( 2010 , 07 , 01 )); LineItem lineItem7 = new LineItem( 2002 , "Item 7" , new Date( 2020 , 07 , 01 )); List<LineItem> lineItemsList2 = new ArrayList<>(); lineItemsList2.add(lineItem6); lineItemsList2.add(lineItem7); Customer customer2 = new Customer( 200 , "Customer 2" , true , "F" , lineItemsList2); |
Creating Customer object 3
01 02 03 04 05 06 07 08 09 10 | LineItem lineItem8 = new LineItem( 2003 , "Item 8" , new Date( 2040 , 07 , 01 )); LineItem lineItem9 = new LineItem( 3004 , "Item 9" , new Date( 2070 , 07 , 01 )); LineItem lineItem10 = new LineItem( 3005 , "Item 10" , new Date( 2200 , 07 , 01 )); List<LineItem> lineItemsList3 = new ArrayList<>(); lineItemsList3.add(lineItem8); lineItemsList3.add(lineItem9); lineItemsList3.add(lineItem10); Customer customer3 = new Customer( 300 , "Customer 3" , true , "M" , lineItemsList3); |
Creating Customer object 4
1 2 3 4 5 6 7 8 9 | Customer customer4 = new Customer( 400 , "Customer 4" , true , "F" , new ArrayList<LineItem>()); Adding all 4 countomers to List. List<Customer> customersList = new ArrayList<>(); customersList.add(customer1); customersList.add(customer2); customersList.add(customer3); customersList.add(customer4); |
Using flatMapping() method to find the LineItems by gender.
1 2 3 4 5 | Map<String, Set<LineItem>> itemsByGender = customersList.stream() .collect(Collectors.groupingBy((Customer c) -> c.getGender(), Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.toSet()))); System.out.println( "itemsByGender : " + itemsByGender); |
Output:
1 2 | itemsByGender : {F=[LineItem [itemId= 2001 , itemName=Item 6 , manfacturedDate=Mon Aug 01 00 : 00 : 00 IST 3910 ], LineItem [itemId= 2002 , itemName=Item 7 , manfacturedDate=Sun Aug 01 00 : 00 : 00 IST 3920 ]], M=[LineItem [itemId= 1001 , itemName=Item 1 , manfacturedDate=Mon Aug 01 00 : 00 : 00 IST 3910 ], LineItem [itemId= 1005 , itemName=Item 5 , manfacturedDate=Tue Aug 01 00 : 00 : 00 IST 3950 ], LineItem [itemId= 1004 , itemName=Item 4 , manfacturedDate=Thu Aug 01 00 : 00 : 00 IST 3940 ], LineItem [itemId= 1002 , itemName=Item 2 , manfacturedDate=Sun Aug 01 00 : 00 : 00 IST 3920 ], LineItem [itemId= 1003 , itemName=Item 3 , manfacturedDate=Fri Aug 01 00 : 00 : 00 IST 3930 ], LineItem [itemId= 2003 , itemName=Item 8 , manfacturedDate=Thu Aug 01 00 : 00 : 00 IST 3940 ], LineItem [itemId= 3004 , itemName=Item 9 , manfacturedDate=Sat Aug 01 00 : 00 : 00 IST 3970 ], LineItem [itemId= 3005 , itemName=Item 10 , manfacturedDate=Sun Aug 01 00 : 00 : 00 IST 4100 ]]} |
Finding the count LineItemas count by gender.
Now instead of calling collecting the output of flatMapping() into Set, invoke Collectors.counting() that count the number of Line items by Gender.
1 | Map<String, Long> itemsCountByGender = customersList.stream().collect(Collectors.groupingBy((Customer c) -> c.getGender(),Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.counting()))); |
Output:
1 | itemsCountByGender {F= 2 , M= 8 } |
19. Collectors.maxBy() Example
maxBy() method finds the max element from the stream. To find the max element, we must pass the Comparator implementation to this method as argument.
This method does as same as reducing(BinaryOperator.maxBy(comparator)).
Syntax:
1 | public static <T> Collector<T,?,Optional<T>> maxBy(Comparator<? super T> comparator) |
This method returns the Optional object. This object avoids NullPointerException by using isPresent() method of Optional class.
Example:
Collectors.maxBy() Example to find highest emp id object.
1 2 3 4 5 | Comparator<Employee> empComparator = (e1, e2) -> e1.getId() - e2.getId(); Optional<Employee> empMaxOptional = employeeList.stream().collect(Collectors.maxBy(empComparator)); if (empMaxOptional.isPresent()) { System.out.println( "Max Emp : " +empMaxOptional.get()); } |
Output:
1 | Max Emp : Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ] |
20. Collectors.minBy() Example
minBy() is opposite to the maxBy() method. minBy() method is used to find a minimum element from the Stream. We should pass the
Comparator as an argument.
This method does as same as reducing(BinaryOperator.minBy(comparator)).
Syntax:
1 | public static <T> Collector<T,?,Optional<T>> maxBy(Comparator<? super T> comparator) |
This method also returns an Optional instance similar to the maxBy() method.
Example:
Collectors.minBy() Example to find min emp id object.
1 2 3 4 | Optional<Employee> empminOptional = employeeList.stream().collect(Collectors.minBy(empComparator)); if (empminOptional.isPresent()) { System.out.println( "Min Emp : " + empminOptional.get()); } |
Output:
1 | Min Emp : Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ] |
21. Collectors.reducing() Example
Returns a Collector which performs a reduction of its input elements under a specified BinaryOperator. The result is described as an Optional<T>.
Syntax:
1 2 3 | public static <T> Collector<T,?,Optional<T>> reducing(BinaryOperator<T> op) public static <T> Collector<T,?,T> reducing(T identity, BinaryOperator<T> op) public static <T,U> Collector<T,?,U> reducing(U identity, Function<? super T,? extends U> mapper, BinaryOperator<U> op) |
Example:
1 2 3 4 5 | // Collectors.reducing() Example Optional<Employee> reducingOptinal = employeeList.stream().collect(Collectors.reducing(BinaryOperator.minBy(empComparator))); if (reducingOptinal.isPresent()) { System.out.println( "Min Emp using reducing() method : " + reducingOptinal.get()); } |
Output:
Min Emp using reducing() method : Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0]
We can find the max emp element using maxBy static method of BinaryOperator.
22. Collectors.summarizingDouble() / summarizingInt() / summarizingLong() Example
summarizingDouble() method does statistics operations on double values in the stream.
This method returns DoubleSummaryStatistics which holds count, min, max, sum, and the average for all double values in the stream. This helps like a utility method.
Syntax:
1 | public static <T> Collector<T,?,DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) |
Example:
1 2 | DoubleSummaryStatistics doubleSummaryStatistics = employeeList.stream().collect(Collectors.summarizingDouble((Employee e) -> e.getSal())); System.out.println( "Statistics summary on employees salary : " +doubleSummaryStatistics); |
Output:
1 | DoubleSummaryStatistics{count= 4 , sum= 1400000.000000 , min= 50000.000000 , average= 350000.000000 , max= 450000.000000 } |
In the same way for Integer and Long values separate methods provided to get the statistics using summarizingInt() and summarizingLong().
1 2 | public static <T> Collector<T,?,LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) public static <T> Collector<T,?,IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) |
23. Collectors.teeing() Example
teeing() method is used to combine two Collectors output using a special merger function. This method is added in Java 12.
Syntax:
1 | public static <T,R1,R2,R> Collector<T,?,R> teeing(Collector<? super T,?,R1> downstream1, Collector<? super T,?,R2> downstream2, BiFunction<? super R1,? super R2,R> merger) |
The above syntax is difficult to understand and simplified as below.
1 | public static Collector teeing(Collector collector1, Collector collector2, BiFunction merger) |
Simple words, This method accepts two collectors and one merger function. Merger function takes outputs of two collectors and performs operations. Finally, returns some value or object or maybe collection.
Example:
Collectors teeing() example to find the average of first 100 numbers.
1 2 3 4 5 6 7 8 9 | // Converting 1 to 100 numbers into Stream integer. List<Integer> intList = new ArrayList<>(); IntStream.range( 1 , 100 ).forEach(i -> intList.add(i)); // Calling teeing method. Double average = intList.stream().collect( Collectors.teeing(Collectors.summingDouble(i -> i), Collectors.counting(), (sum, n) -> sum / n)); System.out.println( "Average of first 100 numbers: " + average); |
Collector 1: Finds the sum of 100 numbers from the stream.
1 | Collectors.summingDouble(i -> i) |
Collector 2: Finds count of numbers in the stream.
1 | Collectors.counting() |
Merger: Takes sum and count as input and does the average operation.
1 | (sum, n) -> sum / n) |
Output:
1 | Average of first 100 numbers: 50.0 |
24. Complete Collectors Methods Examples
All Collectors utility class all methods with examples in a single program.
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | import java.util.ArrayList; import java.util.Comparator; import java.util.Date; import java.util.DoubleSummaryStatistics; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; /** * Java 8 Collectors api Examples * * @author Venkatesh * */ public class Java8CollectorExamples { public static void main(String[] args) { // Creating a Employee List - Example List<Employee> employeeList = new ArrayList<>(); employeeList.add( new Employee( 100 , "Sundar" , 47 , "North America" , 450000 )); employeeList.add( new Employee( 200 , "Pichai" , 25 , "North America" , 50000 )); employeeList.add( new Employee( 300 , "Larry" , 30 , "Asia" , 450000 )); employeeList.add( new Employee( 400 , "Page" , 59 , "Africa" , 450000 )); // Collectors.toList() Example List<String> namesList = employeeList.stream().map(e -> e.getName()).collect(Collectors.toList()); System.out.println(namesList); // Collectors.toSet() Example Set<String> regionSet = employeeList.stream().map(e -> e.getRegion()).collect(Collectors.toSet()); System.out.println(regionSet); regionSet.add( "hello" ); System.out.println(regionSet); // Collectors.toUnmodifiableSet() Example Set<Double> unmodifiableSet = employeeList.stream().map(e -> e.getSal()) .collect(Collectors.toUnmodifiableSet()); System.out.println(unmodifiableSet); // unmodifiableSet.add(10983d); // employeeList.add(null); Set<Employee> empSet = employeeList.stream().collect(Collectors.toUnmodifiableSet()); // Collectors.toUnmodifiableList(() Example // employeeList.add(null); List<Double> unmodifiableList = employeeList.stream().map(e -> e.getSal()) .collect(Collectors.toUnmodifiableList()); System.out.println(unmodifiableList); // Collectors.toCollection() Example List<String> namesLinkedList = employeeList.stream().map(e -> e.getName()) .collect(Collectors.toCollection(LinkedList:: new )); System.out.println(namesLinkedList); Set<String> regionTreeSet = employeeList.stream().map(e -> e.getRegion()) .collect(Collectors.toCollection(TreeSet:: new )); System.out.println(regionTreeSet); // Collectors.toMap() Example Map<Integer, Employee> empMap = employeeList.stream() .collect(Collectors.toMap((e) -> e.getId(), Function.identity())); System.out.println(empMap); // with duplicate key. uncomment to work with toMap() for duplicate merger. // employeeList.add(new Employee(400, "Larry Page", 59, "Africa", 450000)); Map<Integer, Employee> empDupMap = employeeList.stream() .collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp)); System.out.println(empDupMap); // Collectors.toUnmodifiableMap() Example Map<Integer, Employee> empUnmodifiedMap = employeeList.stream() .collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp)); System.out.println(empUnmodifiedMap); // Collector.summingInt() Example int sumOfEmpIds = employeeList.stream().collect(Collectors.summingInt((Employee e) -> e.getId())); System.out.println( "Collectors.summingInt : " + sumOfEmpIds); // Collector.summingInt() Example double sumOfEmpSalss = employeeList.stream().collect(Collectors.summingDouble((Employee e) -> e.getSal())); System.out.println( "Collectors.summingDouble : " + sumOfEmpSalss); // Collectors.averagingInt() / averagingLong() / averagingDouble() Examples double avgOfEmpSalss = employeeList.stream().collect(Collectors.averagingDouble((Employee e) -> e.getSal())); System.out.println( "Collectors.averagingDouble avg sal: " + avgOfEmpSalss); // Collectors.counting() Example long count = employeeList.stream().collect(Collectors.counting()); System.out.println( "Collectors.counting() : Count : " + count); // Collectors.joining() Example String joinedStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining()); System.out.println( "joinedStr by using joining() method : " + joinedStr); String joinedDelimiterStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining( " * " )); System.out.println( "joinedDelimiterStr by using joining(Delimiter) method : " + joinedDelimiterStr); String joinePrePostStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining( "*" , "@" , "|" )); System.out.println( "joinePrePostStr by using joining(Delimiter) method : " + joinePrePostStr); // Collectors.groupingBy() Example Map<String, List<Employee>> groupByRegion = employeeList.stream() .collect(Collectors.groupingBy((Employee e) -> e.getRegion())); System.out.println( "groupByRegion :: " + groupByRegion); // groupingBy for set. Map<String, Set<Employee>> groupByRegionSet = employeeList.stream() .collect(Collectors.groupingBy((Employee e) -> e.getRegion(), Collectors.toSet())); System.out.println( "groupByRegionSet :: " + groupByRegionSet); // Collectors.partitioningBy() Example Map<Boolean, List<Employee>> partitionByAge = employeeList.stream() .collect(Collectors.partitioningBy(e -> e.getAge() > 30 )); System.out.println( "partitionByAge :: " + partitionByAge); // Set as Map value Map<Boolean, Set<Employee>> partitionByAgeSet = employeeList.stream() .collect(Collectors.partitioningBy(e -> e.getAge() > 30 , Collectors.toSet())); // LinkedList as Map value Map<Boolean, LinkedList<Employee>> partitionByAgeLinedList = employeeList.stream() .collect(Collectors.partitioningBy(e -> e.getAge() > 30 , Collectors.toCollection(LinkedList:: new ))); // TreeSet as Map value /* * Map<Boolean, TreeSet<Employee>> partitionByAgeTreeSet = employeeList.stream() * .collect(Collectors.partitioningBy(e -> e.getAge() > 30, * Collectors.toCollection(TreeSet::new))); */ // Collectors.toConcurrentMap() Example Map<Integer, Employee> empConcurrentMap = employeeList.stream() .collect(Collectors.toConcurrentMap((e) -> e.getId(), Function.identity())); System.out.println(empConcurrentMap); // with duplicate key. uncomment to work with toMap() for duplicate merger. // employeeList.add(new Employee(400, "Larry Page", 59, "Africa", 450000)); Map<Integer, Employee> empDupConcurrentMap = employeeList.stream() .collect(Collectors.toConcurrentMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp)); System.out.println(empDupMap); // Collectors.filtering() Example List<Employee> filteredEmpList = employeeList.stream() .collect(Collectors.filtering((Employee e) -> e.getAge() > 30 , Collectors.toList())); System.out.println( "Collectors.filtering() - filteredEmpList : " + filteredEmpList); // Collectors.flatMapping() Example LineItem lineItem1 = new LineItem( 1001 , "Item 1" , new Date( 2010 , 07 , 01 )); LineItem lineItem2 = new LineItem( 1002 , "Item 2" , new Date( 2020 , 07 , 01 )); LineItem lineItem3 = new LineItem( 1003 , "Item 3" , new Date( 2030 , 07 , 01 )); LineItem lineItem4 = new LineItem( 1004 , "Item 4" , new Date( 2040 , 07 , 01 )); LineItem lineItem5 = new LineItem( 1005 , "Item 5" , new Date( 2050 , 07 , 01 )); List<LineItem> lineItemsList1 = new ArrayList<>(); lineItemsList1.add(lineItem1); lineItemsList1.add(lineItem2); lineItemsList1.add(lineItem3); lineItemsList1.add(lineItem4); lineItemsList1.add(lineItem5); Customer customer1 = new Customer( 100 , "Customer 1" , true , "M" , lineItemsList1); LineItem lineItem6 = new LineItem( 2001 , "Item 6" , new Date( 2010 , 07 , 01 )); LineItem lineItem7 = new LineItem( 2002 , "Item 7" , new Date( 2020 , 07 , 01 )); List<LineItem> lineItemsList2 = new ArrayList<>(); lineItemsList2.add(lineItem6); lineItemsList2.add(lineItem7); Customer customer2 = new Customer( 200 , "Customer 2" , true , "F" , lineItemsList2); LineItem lineItem8 = new LineItem( 2003 , "Item 8" , new Date( 2040 , 07 , 01 )); LineItem lineItem9 = new LineItem( 3004 , "Item 9" , new Date( 2070 , 07 , 01 )); LineItem lineItem10 = new LineItem( 3005 , "Item 10" , new Date( 2200 , 07 , 01 )); List<LineItem> lineItemsList3 = new ArrayList<>(); lineItemsList3.add(lineItem8); lineItemsList3.add(lineItem9); lineItemsList3.add(lineItem10); Customer customer3 = new Customer( 300 , "Customer 3" , true , "M" , lineItemsList3); Customer customer4 = new Customer( 400 , "Customer 4" , true , "F" , new ArrayList<LineItem>()); List<Customer> customersList = new ArrayList<>(); customersList.add(customer1); customersList.add(customer2); customersList.add(customer3); customersList.add(customer4); Map<String, Set<LineItem>> itemsByGender = customersList.stream() .collect(Collectors.groupingBy((Customer c) -> c.getGender(), Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.toSet()))); System.out.println( "itemsByGender : " + itemsByGender); Map<String, Long> itemsCountByGender = customersList.stream() .collect(Collectors.groupingBy((Customer c) -> c.getGender(), Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.counting()))); System.out.println( "itemsCountByGender " + itemsCountByGender); // Collectors.maxBy() Example Comparator<Employee> empComparator = (e1, e2) -> e1.getId() - e2.getId(); Optional<Employee> empMaxOptional = employeeList.stream().collect(Collectors.maxBy(empComparator)); if (empMaxOptional.isPresent()) { System.out.println( "Max Emp : " + empMaxOptional.get()); } // Collectors.minBy() Example Optional<Employee> empminOptional = employeeList.stream().collect(Collectors.minBy(empComparator)); if (empminOptional.isPresent()) { System.out.println( "Min Emp : " + empminOptional.get()); } // Collectors.reducing() Example Optional<Employee> reducingOptinal = employeeList.stream() .collect(Collectors.reducing(BinaryOperator.minBy(empComparator))); if (reducingOptinal.isPresent()) { System.out.println( "Min Emp using reducing() method : " + reducingOptinal.get()); } // Collectors.summarizingDouble() Example DoubleSummaryStatistics doubleSummaryStatistics = employeeList.stream() .collect(Collectors.summarizingDouble((Employee e) -> e.getSal())); System.out.println( "Statistics summary on employees salary : " + doubleSummaryStatistics); // Converting 1 to 100 numbers into Stream integer. List<Integer> intList = new ArrayList<>(); IntStream.range( 1 , 100 ).forEach(i -> intList.add(i)); // Calling teeing method. Double average = intList.stream().collect( Collectors.teeing(Collectors.summingDouble(i -> i), Collectors.counting(), (sum, n) -> sum / n)); System.out.println( "Average of first 100 numbers: " + average); } } |
Output:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | [Sundar, Pichai, Larry, Page] [Asia, Africa, North America] [Asia, Africa, hello, North America] [ 50000.0 , 450000.0 ] [ 450000.0 , 50000.0 , 450000.0 , 450000.0 ] [Sundar, Pichai, Larry, Page] [Africa, Asia, North America] { 400 =Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ], 100 =Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], 200 =Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], 300 =Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]} { 400 =Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ], 100 =Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], 200 =Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], 300 =Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]} { 400 =Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ], 100 =Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], 200 =Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], 300 =Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]} Collectors.summingInt : 1000 Collectors.summingDouble : 1400000.0 Collectors.averagingDouble avg sal: 350000.0 Collectors.counting() : Count : 4 joinedStr by using joining() method : SundarPichaiLarryPage joinedDelimiterStr by using joining(Delimiter) method : Sundar * Pichai * Larry * Page joinePrePostStr by using joining(Delimiter) method : @Sundar *Pichai*Larry*Page| groupByRegion :: {Asia=[Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]], Africa=[Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]], North America=[Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ]]} groupByRegionSet :: {Asia=[Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]], Africa=[Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]], North America=[Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ]]} partitionByAge :: { false =[Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]], true =[Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]]} { 400 =Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ], 100 =Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], 200 =Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], 300 =Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]} { 400 =Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ], 100 =Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], 200 =Employee [id= 200 , name=Pichai, age= 25 , region=North America, sal= 50000.0 ], 300 =Employee [id= 300 , name=Larry, age= 30 , region=Asia, sal= 450000.0 ]} Collectors.filtering() - filteredEmpList : [Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ], Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ]] itemsByGender : {F=[LineItem [itemId= 2001 , itemName=Item 6 , manfacturedDate=Mon Aug 01 00 : 00 : 00 IST 3910 ], LineItem [itemId= 2002 , itemName=Item 7 , manfacturedDate=Sun Aug 01 00 : 00 : 00 IST 3920 ]], M=[LineItem [itemId= 1001 , itemName=Item 1 , manfacturedDate=Mon Aug 01 00 : 00 : 00 IST 3910 ], LineItem [itemId= 1005 , itemName=Item 5 , manfacturedDate=Tue Aug 01 00 : 00 : 00 IST 3950 ], LineItem [itemId= 1004 , itemName=Item 4 , manfacturedDate=Thu Aug 01 00 : 00 : 00 IST 3940 ], LineItem [itemId= 1002 , itemName=Item 2 , manfacturedDate=Sun Aug 01 00 : 00 : 00 IST 3920 ], LineItem [itemId= 1003 , itemName=Item 3 , manfacturedDate=Fri Aug 01 00 : 00 : 00 IST 3930 ], LineItem [itemId= 2003 , itemName=Item 8 , manfacturedDate=Thu Aug 01 00 : 00 : 00 IST 3940 ], LineItem [itemId= 3004 , itemName=Item 9 , manfacturedDate=Sat Aug 01 00 : 00 : 00 IST 3970 ], LineItem [itemId= 3005 , itemName=Item 10 , manfacturedDate=Sun Aug 01 00 : 00 : 00 IST 4100 ]]} itemsCountByGender {F= 2 , M= 8 } Max Emp : Employee [id= 400 , name=Page, age= 59 , region=Africa, sal= 450000.0 ] Min Emp : Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ] Min Emp using reducing() method : Employee [id= 100 , name=Sundar, age= 47 , region=North America, sal= 450000.0 ] Statistics summary on employees salary : DoubleSummaryStatistics{count= 4 , sum= 1400000.000000 , min= 50000.000000 , average= 350000.000000 , max= 450000.000000 } Average of first 100 numbers: 50.0 |
25. Conclusion
In this tutorial, We have covered in-depth on Collectors API.
First, Covered the introduction to the Collectors api and what it does.
Next, Shown the example programs on each and every method of Collectors.
All methods are declared as Static in Collectors class. So, Directly methods can be accessed with class name E.g. Collectors.toList(), Collectors.groupingBy() etc.
Commonly used method of Collectors are toList(), toMap(), toCollection(), joining(), summingInt(), groupingBy() and partitioningBy().
All the examples shown are available over GitHub.
Published on Java Code Geeks with permission by Venkatesh Nukala, partner at our JCG program. See the original article here: Java 8 Collectors API Tutorial With Real Time Examples Opinions expressed by Java Code Geeks contributors are their own. |
Some of the methods like Collectors.toUnmodifiableList() and Collectors.filtering are not there in Java 8. Just thought of mentioning because the title says Java 8 collectors tutorial. But great examples though.
Nice collection of examples