Core Java

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:

  1. collect()
  2. toList()
  3. toSet()
  4. toUnmodifiableSet()
  5. toUnmodifiableList(()
  6. toCollection()
  7. toMap()
  8. toUnmodifiableMap()
  9. summingInt()
  10. averagingInt() / averagingLong() / averagingDouble()s
  11. counting()
  12. joining()
  13. groupingBy()
  14. partitioningBy()
  15. toConcurrentMap()
  16. filtering()
  17. flatMapping()
  18. maxBy()
  19. minBy()
  20. reducing()
  21. summarizingDouble() / summarizingInt() / summarizingLong()
  22. 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.

Venkatesh Nukala

Venkatesh Nukala is a Software Engineer working for Online Payments Industry Leading company. In my free time, I would love to spend time with family and write articles on technical blogs. More on JavaProgramTo.com
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Karthick
Karthick
3 years ago

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.

Harish Kotkar
Harish Kotkar
2 years ago

Nice collection of examples

Back to top button