Saturday, 15 August 2015

Java8: Collectors

Collectors class offer three functionalities.
1.   Summarizing/Reducing elements according to certain criteria
2.   Grouping elements
3. Partitioning elements.

1. Summarizing elements according to certain criteria
Collectors class provides following methods to summarize/reduce elements according to certain criteria. I suggest you to go through following examples first, then come to this table.
Method
Description
public static <T> Collector<T, ?, Long> counting()
Returns a Collector accepting elements of type T that counts the number of input elements.
public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator)
Returns a Collector that produces the maximal element according to a given Comparator.
public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator)
Returns a Collector that produces the minimal element according to a given Comparator.
public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper)
Returns a Collector that produces the sum of a double-valued function applied to the input elements.
public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper)
Returns a Collector that produces the sum of a integer-valued function applied to the input elements.
public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper)
Returns a Collector that produces the sum of a long-valued function applied to the input elements.
public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper)
Returns a Collector that produces the average of a double-valued function applied to the input elements.
public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper)
Returns a Collector that produces the average of a integer-valued function applied to the input elements.
public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper)
Returns a Collector that produces the average of a long-valued function applied to the input elements
public static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)
Returns a Collector implementing the summary-statistics reduction
public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)
Returns a Collector implementing the summary-statistics reduction
public static <T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
Returns a Collector implementing the summary-statistics reduction
public static Collector<CharSequence, ?, String> joining()
Returns a Collector that concatenates the input elements into a String.
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter)
Returns a Collector that concatenates the input elements, separated by the specified delimiter, in encounter order.
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
Returns a Collector that concatenates the input elements, separated by the specified delimiter, with the specified prefix and suffix, in encounter order.

a. Count number employees who are staying at Chennai.
employees.stream().filter((emp) -> emp.getCity().equals("Chennai")).collect(Collectors.counting());

b. Find maximum salaried employee
employees.stream().collect(Collectors.maxBy(comparing(Employee::getSalary)));

c. Find minimum salaried employee
employees.stream().collect(Collectors.minBy(comparing(Employee::getSalary)));

d. Find total salary of all employees
employees.stream().collect(Collectors.summingDouble(Employee::getSalary))

e. Find average salary of all employees
employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));

d. Find number of employees, sum of their salaries, maximum, minimum and average of salaries in single statement.
You can do this by using summarizingDouble method.

employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));

Above statement return following result.

DoubleSummaryStatistics{count=10, sum=868686.000000, min=35000.000000, average=86868.600000, max=198765.000000}

e. Find all employee firstNames separated by ,.
employees.stream().map(Employee::getFirstName).collect(Collectors.joining(","));

2. Grouping Elements
Collectors class provides following methods to group elements.

Method
Description
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
Returns a  Collector implementing a "group by" operation on input elements of type T, grouping elements according to a classification function, and returning the results in a Map.
public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)
It is just like above function, used to group elements on multiple properties.


a.Group employees by city
Map<String, List<Employee>> groupByCity = employees.stream().collect(Collectors.groupingBy(Employee::getCity));

Above statement returns following output.

{Chennai=[Shanmukh(Chennai,28,35000.000000), Harika(Chennai,27,76000.000000)], Trivendram=[Raju(Trivendram,40,198765.000000), Brijesh(Trivendram,34,100000.000000)], Hyderabad=[Joel(Hyderabad,27,50000.000000), PTR(Hyderabad,27,123456.000000), Siva krishna(Hyderabad,28,98765.000000)], Bangalore=[Hari Krishna(Bangalore,26,40000.000000), Sudheer(Bangalore,27,90000.000000), Rama Krishna(Bangalore,27,56700.000000)]}

b. Group Employees by age
employees.stream().collect(Collectors.groupingBy(Employee::getAge));

c. Group employees by city and age.
employees.stream().collect(Collectors.groupingBy(Employee::getCity,Collectors.groupingBy(Employee::getAge)));

3. Partitioning elements
Partitioning is a special kind of grouping, it divides elements into two disjoint sets, one contains elements that match given predicate and other contains elements that don’t match given predicate.

Collectors class provides following methods to partition elements.
Method
Description
public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)
Returns a Collector which partitions the input elements according to a Predicate, and organizes them into a Map<Boolean, List<T>>.
public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,Collector<? super T, A, D> downstream)
Returns a Collector which partitions the input elements according to a Predicate, reduces the values in each partition according to another Collector, and organizes them into a Map<Boolean, D> whose values are the result of the downstream reduction.

a. Get all employees who are staying in Chennai and who are not staying in Chennai
Map<Boolean, List<Employee>> partitionEmp = employees.stream().collect(Collectors.partitioningBy((emp1) -> emp1.getCity().equals("Chennai")));
List<Employee> chennaiEmp = partitionEmp.get(true);
List<Employee> nonChennaiEmp = partitionEmp.get(false);


Find complete working application below.

import java.util.Objects;

public class Employee {
 private int id;
 private String firstName;
 private String lastName;
 private int age;
 private String city;
 private double salary;

 public Employee(int id, String firstName, String lastName, int age,
   String city, double salary) {
  super();
  this.id = id;
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.city = city;
  this.salary = salary;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public String getCity() {
  return city;
 }

 public void setCity(String city) {
  this.city = city;
 }

 public double getSalary() {
  return salary;
 }

 public void setSalary(double salary) {
  this.salary = salary;
 }

 @Override
 public boolean equals(Object employee) {
  if (Objects.isNull(employee))
   return false;

  if (!(employee instanceof Employee))
   return false;

  Employee emp = (Employee) employee;

  return id == emp.id;
 }

 @Override
 public int hashCode() {
  return Objects.hash(id, firstName, lastName, age);
 }

 @Override
 public String toString() {
  return String.format("%s(%s,%d,%f)", firstName, city, age, salary);
 }

}


import static java.util.Comparator.comparing;

import java.util.ArrayList;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class Test {
 public static List<Employee> getEmployees() {
  Employee emp1 = new Employee(1, "Hari Krishna", "Gurram", 26,
    "Bangalore", 40000);
  Employee emp2 = new Employee(2, "Joel", "Chelli", 27, "Hyderabad",
    50000);
  Employee emp3 = new Employee(3, "Shanmukh", "Kummary", 28, "Chennai",
    35000);
  Employee emp4 = new Employee(4, "Harika", "Raghuram", 27, "Chennai",
    76000);
  Employee emp5 = new Employee(5, "Sudheer", "Ganji", 27, "Bangalore",
    90000);
  Employee emp6 = new Employee(6, "Rama Krishna", "Gurram", 27,
    "Bangalore", 56700);
  Employee emp7 = new Employee(7, "PTR", "PTR", 27, "Hyderabad", 123456);
  Employee emp8 = new Employee(8, "Siva krishna", "Ponnam", 28,
    "Hyderabad", 98765);
  Employee emp9 = new Employee(9, "Raju", "Antony", 40, "Trivendram",
    198765);
  Employee emp10 = new Employee(10, "Brijesh", "Krishnan", 34,
    "Trivendram", 100000);

  List<Employee> employees = new ArrayList<>();

  employees.add(emp1);
  employees.add(emp2);
  employees.add(emp3);
  employees.add(emp4);
  employees.add(emp5);
  employees.add(emp6);
  employees.add(emp7);
  employees.add(emp8);
  employees.add(emp9);
  employees.add(emp10);

  return employees;
 }

 public static void main(String args[]) {
  List<Employee> employees = getEmployees();

  /* Count number of employees who are stying in Chennai */
  long noOfEmployees = employees.stream()
    .filter((emp) -> emp.getCity().equals("Chennai"))
    .collect(Collectors.counting());
  System.out.println("Number Of employees in Chennai" + noOfEmployees
    + "\n");

  /* Find maximum salaried employee */
  Optional<Employee> emp = employees.stream().collect(
    Collectors.maxBy(comparing(Employee::getSalary)));
  System.out.println("Maximum salaried employee" + emp + "\n");

  /* Find maximum salaried employee */
  emp = employees.stream().collect(
    Collectors.minBy(comparing(Employee::getSalary)));
  System.out.println("Minimum salaried employee" + emp + "\n");

  /* Find total salary of all employees */
  double totalSalary = employees.stream().collect(
    Collectors.summingDouble(Employee::getSalary));
  System.out.println("Totala salry is " + totalSalary + "\n");

  /* Find average salary of all employees */
  double avgSalary = employees.stream().collect(
    Collectors.averagingDouble(Employee::getSalary));
  System.out.println("Average saary of employees is" + avgSalary + "\n");

  /*
   * Find number of employees, sum of their salaries, maximum, minimum and
   * average of salaries in single statement.
   */
  DoubleSummaryStatistics statistics = employees.stream().collect(
    Collectors.summarizingDouble(Employee::getSalary));
  System.out.println(statistics + "\n");

  /* Find all employee firstNames separated by ,. */
  String firstNames = employees.stream().map(Employee::getFirstName)
    .collect(Collectors.joining(","));
  System.out.println(firstNames + "\n");

  /* Group employees by city */
  Map<String, List<Employee>> groupByCity = employees.stream().collect(
    Collectors.groupingBy(Employee::getCity));
  System.out.println(groupByCity + "\n");

  /* Group employees by age */
  Map<Integer, List<Employee>> groupByAge = employees.stream().collect(
    Collectors.groupingBy(Employee::getAge));
  System.out.println(groupByAge + "\n");

  /* Group employees by city and age */
  Map<String, Map<Integer, List<Employee>>> groupByCityAndAge = employees
    .stream().collect(
      Collectors.groupingBy(Employee::getCity,
        Collectors.groupingBy(Employee::getAge)));
  System.out.println(groupByCityAndAge + "\n");

  /*
   * Get all employees who are staying in Chennai and who are not staying
   * in Chennai
   */
  Map<Boolean, List<Employee>> partitionEmp = employees.stream().collect(
    Collectors.partitioningBy((emp1) -> emp1.getCity().equals(
      "Chennai")));
  List<Employee> chennaiEmp = partitionEmp.get(true);
  List<Employee> nonChennaiEmp = partitionEmp.get(false);

  System.out.println(chennaiEmp + "\n");
  System.out.println(nonChennaiEmp);

 }
}


Output

Number Of employees in Chennai2

Maximum salaried employeeOptional[Raju(Trivendram,40,198765.000000)]

Minimum salaried employeeOptional[Shanmukh(Chennai,28,35000.000000)]

Totala salry is 868686.0

Average saary of employees is86868.6

DoubleSummaryStatistics{count=10, sum=868686.000000, min=35000.000000, average=86868.600000, max=198765.000000}

Hari Krishna,Joel,Shanmukh,Harika,Sudheer,Rama Krishna,PTR,Siva krishna,Raju,Brijesh

{Chennai=[Shanmukh(Chennai,28,35000.000000), Harika(Chennai,27,76000.000000)], Trivendram=[Raju(Trivendram,40,198765.000000), Brijesh(Trivendram,34,100000.000000)], Hyderabad=[Joel(Hyderabad,27,50000.000000), PTR(Hyderabad,27,123456.000000), Siva krishna(Hyderabad,28,98765.000000)], Bangalore=[Hari Krishna(Bangalore,26,40000.000000), Sudheer(Bangalore,27,90000.000000), Rama Krishna(Bangalore,27,56700.000000)]}

{34=[Brijesh(Trivendram,34,100000.000000)], 40=[Raju(Trivendram,40,198765.000000)], 26=[Hari Krishna(Bangalore,26,40000.000000)], 27=[Joel(Hyderabad,27,50000.000000), Harika(Chennai,27,76000.000000), Sudheer(Bangalore,27,90000.000000), Rama Krishna(Bangalore,27,56700.000000), PTR(Hyderabad,27,123456.000000)], 28=[Shanmukh(Chennai,28,35000.000000), Siva krishna(Hyderabad,28,98765.000000)]}

{Chennai={27=[Harika(Chennai,27,76000.000000)], 28=[Shanmukh(Chennai,28,35000.000000)]}, Trivendram={34=[Brijesh(Trivendram,34,100000.000000)], 40=[Raju(Trivendram,40,198765.000000)]}, Hyderabad={27=[Joel(Hyderabad,27,50000.000000), PTR(Hyderabad,27,123456.000000)], 28=[Siva krishna(Hyderabad,28,98765.000000)]}, Bangalore={26=[Hari Krishna(Bangalore,26,40000.000000)], 27=[Sudheer(Bangalore,27,90000.000000), Rama Krishna(Bangalore,27,56700.000000)]}}

[Shanmukh(Chennai,28,35000.000000), Harika(Chennai,27,76000.000000)]

[Hari Krishna(Bangalore,26,40000.000000), Joel(Hyderabad,27,50000.000000), Sudheer(Bangalore,27,90000.000000), Rama Krishna(Bangalore,27,56700.000000), PTR(Hyderabad,27,123456.000000), Siva krishna(Hyderabad,28,98765.000000), Raju(Trivendram,40,198765.000000), Brijesh(Trivendram,34,100000.000000)]


Prevoius                                                 Next                                                 Home

No comments:

Post a Comment