Java 8 – How to use Collectors.toCollection Collector with examples

This tutorial explains how to use Java 8’s predefined collector returned by Collectors.toCollection() method with examples. It first explains the definition of the static toCollection() method, followed by a quick explanation of its working, and then shows how to use Collector returned by Collectors.toCollection() using two Java 8 code examples.

Collectors.toCollection() method
Collectors.toCollection() method is defined with the following signature –

public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory)

Where,
     – only input parameter is collectionFactory which is an instance of a SupplierClick to Read Tutorial on Supplier Functional Interface functional interface.
     – output is a Collector with result containerClick to Read tutorial explaining collector internals incl. ‘result container’ as a Collection of type T.

How the Collector returned by Collectors.toCollection() method works
The collector returned by Collector.toCollection() method stores(collects) the stream elements in an object of a subtype of java.util.Collection.

Which specific type of subtype Collection to use is specified to the collector using the collectionFactory input parameter which is a Supplier functional interface. A Supplier’s task is to supply objects of a given type. In this case, the supplier passed to the toCollection() method needs to ‘supply’ a concrete Collection instance in order for the collector to work.

So, when the stream elements reach the Stream.collect() method with a toCollection collector, the Collector invokes the Supplier, in return gets an object of the Collection subtype it supplies, and then collects the stream elements into the supplied Collection object. This Collection object, containing the collected stream elements, is then returned as the output of the processed stream.

To complete our understanding of how the toCollection Collector works, let us see couple of Java 8 code examples which show the collector in action.

Example 1 - Java 8 Code showing Collectors.toCollection() usage
//ToCollectionCollector.java
package com.javabrahman.java8.collector;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
public class ToCollectionCollector {
  static List<Employee> employeeList
      = Arrays.asList(new Employee("Tom Jones", 45, 15000.00),
      new Employee("Tom Jones", 45, 7000.00),
      new Employee("Ethan Hardy", 65, 8000.00),
      new Employee("Nancy Smith", 22, 10000.00),
      new Employee("Deborah Sprightly", 29, 9000.00));

  public static void main(String[] args) {
    //Collecting stream elements in a LinkedList
    LinkedList employeeLinkedList = employeeList
        .stream()
        .collect(Collectors.toCollection(LinkedList::new));
    System.out.println("No.of employees in employeeLinkedList: " + employeeLinkedList.size());
    System.out.println("Employees in employeeLinkedList: " + employeeLinkedList);
  }
}

//Employee.java(POJO class)
package com.javabrahman.java8.collector;
public class Employee {

  private String name;
  private Integer age;
  private Double salary;

  public Employee(String name, Integer age, Double salary) {
    this.name = name;
    this.age = age;
    this.salary = salary;
  }

  //Setters and Getters for name, age & salary go here

  public String toString(){
    return "Name: "+ this.name
        + " Age: "+ this.age;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    }
    if (!(obj instanceof Employee)) {
      return false;
    }
    Employee empObj = (Employee) obj;
    return this.age == empObj.age
        && this.name.equalsIgnoreCase(empObj.name);
  }

  @Override
  public int hashCode() {
    int hash = 1;
    hash = hash * 17 + this.name.hashCode();
    hash = hash * 31 + this.age;
    return hash;
  }
}
 OUTPUT of the above code
No.of employees in employeeLinkedList: 5
Employees in employeeLinkedList: [Name: Tom Jones Age: 45, Name: Tom Jones Age: 45, Name: Ethan Hardy Age: 65, Name: Nancy Smith Age: 22, Name: Deborah Sprightly Age: 29]
Explanation of the code

  • ToCollectionCollector class contains a static list of Employee objects – employeeList.
  • In the main() method a stream of Employee objects is created using List.stream() method.
  • Stream of employees is then pipelined to the collect() terminal operationClick to Read Tutorial explaining intermediate & terminal Stream operations.
  • To the collect() method, Collector returned by Collectors.toCollection() method is passed as a parameter.
  • toCollection collector is invoked with the input “LinkedList::new”, which is a method reference
    Click to Read Tutorial on Java 8’s Method References
    , to the LinkedList’s default constructor .
  • toCollection collector then collects the Employee objects in the stream in an instance of LinkedList and returns this linked list as the output of stream processing.
  • Collected LinkedList is assigned to a parameter named employeeLinkedList. The size of the linked list and its contents are then printed. As expected, the linked list has 5 Employee objects, and all the 5 objects are printed with their name and age.

(Note – The Employee class and employeeList objects with their values remain the same as the previous code usage example and hence are not shown again in example 2 below for brevity.)

Example 2 - Collectors.toCollection() in action
  public static void main(String[] args) {
    //Collecting stream elements in a HashSet
    HashSet employeeHashSet = employeeList
        .stream()
        .collect(Collectors.toCollection(HashSet::new));
    System.out.println("No.of employees in employeeHashSet: " + employeeHashSet.size());
    System.out.println("Employees in employeeHashSet: " + employeeHashSet);
  }
 OUTPUT of the above code
No.of employees in employeeHashSet: 4
Employees in employeeHashSet: [Name: Tom Jones Age: 45, Name: Ethan Hardy Age: 65, Name: Deborah Sprightly Age: 29, Name: Nancy Smith Age: 22]
Explanation of the code

  • The Employee objects in the stream are collected, with the Supplier input to the toCollection() method being the method reference to the default HashSet constructor – HashSet::new”.
  • The collected Employee objects are then returned in a HashSet instance and assigned to employeeHashSet variable.
  • The count of collected employees is then printed along with the employeeHashSet contents.
  • However, this time the number of employee objects in employeeHashSet comes out to be 4.
  • If you observe closely in the output to see which Employee object is missing, then you will see that 1 out of 2 "Tom Jones"(employee name) objects is missing. This is however the correct output. This is because, both the “Tom Jones” objects have the same name and age, their salary being different. But equals() implementation in Employee only checks for name and age to determine equality. As a result, the HashSet insertion logic finds these two objects to be equal and only stores one of them, as a HashSet cannot store duplicate objects by design.

 

Digiprove sealCopyright © 2014-2017 JavaBrahman.com, all rights reserved.