Java 8 How to use collectors averagingInt, averagingLong, averagingDouble with examples

This tutorial explains how to use the predefined averaging collectors returned by Collectors.averagingInt(), Collectors.averagingLong() and Collectors.averagingDouble() methods with examples. It first explains the method definitions of these 3 methods and then shows averaging collectors’ usage using Java 8 code example, along with detailed explanation of the code.

Definition of averaging collectors
All 3 averaging collectors have very similar signatures which are as follows –

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)

Where,
     – input for all 3 collectors is a FunctionClick to Read Tutorial on Function functional interfaces which extracts an int/long/double type of value as it works on the objects of the stream.The definitions in fact use the predefined ToIntFunction/ ToLongFunction/ ToDoubleFunction which I will explain in the next section.
     – output is a Collector with finisherClick to Read tutorial on 4 components of Collectors incl. ‘finisher’(return type) of type Double.

How the averaging collector works
Given a stream of objects, averaging collectors provided by the methods Collectors.averagingInt(), Collectors.averagingLong() and Collectors.averagingDouble() reduce these objects to an average of their numerical value/numerical value equivalent.

The average operation in mathematics can be applied to a numeric value only. So to apply the averaging collectors one may assume that the streams need to carry numeric values. Java designers understand that it is not necessary that the objects in the stream themselves may be numeric; rather these objects may have a numerical attribute which needs to be averaged, or their might be some calculation done first on the objects to derive an equivalent numerical value and then average those values. In keeping with this understanding, the only parameter to the averaging collector creation methods accepts a function instance which converts the stream objects to their equivalent numerical values, or, more simply put, these functions extract the numerical value to be averaged from the stream objects.

Since, there already are predefined functions ToIntFunction, ToLongFunction, and ToDoubleFunctions existing in java.util.functionClick to Read Tutorial on Overview of Java 8’s new java.util.function package package for exactly such conversions of objects to their primitive equivalent value in int, long and double respectively, the same have been used for defining the conversion functions used by averaging collector definitions we saw above.

Example showing usage of collectors – averagingInt, averagingLong, averagingDouble
Problem Description: Given a stream of Employee objects, we want to –

  1. Find the average age of employees. Attribute age is of type int.
  2. Find the average leaves(taken) of employees. Attribute leaves is of type long.
  3. Find the average salary of employees. Attribute salary is of type Double.

Solution code for the above problem is –

Java 8 Code Example for averagingInt, averagingLong, averagingDouble
package com.javabrahman.java8.collector;

import com.javabrahman.java8.Employee;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class AveragingWithCollectors {
  static List<Employee> employeeList
      = Arrays.asList(new Employee("Tom Jones", 45, 15000.00,190),
      new Employee("Tom Jones", 45, 7000.00,220),
      new Employee("Ethan Hardy", 65, 8000.00,1008),
      new Employee("Nancy Smith", 22, 10000.00,5),
      new Employee("Deborah Sprightly", 29, 9000.00,45));

  public static void main(String[] args) {
    //Using Collectors.averagingInt()
    Double avgAge = employeeList
        .stream()
        .collect(Collectors.averagingInt(Employee::getAge));
     System.out.println("Average age using Collectors.averagingInt: " + avgAge);

    //Using Collectors.averagingLong()
    Double avgLeaves = employeeList
        .stream()
        .collect(Collectors.averagingLong(Employee::getLeaves));
    System.out.println("Average leaves using Collectors.averagingLong: " + avgLeaves);

    //Using Collectors.averagingDouble()
    Double avgSalary = employeeList
        .stream()
        .collect(Collectors.averagingDouble(Employee::getSalary));
    System.out.println("Average salary using Collectors.averagingDouble: " + avgSalary);
  }
}
//Employee.java POJO class
package com.javabrahman.java8;
import java.text.DecimalFormat;
public class Employee {
  private String name;
  private Integer age;
  private Double salary;
  private long leaves;

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

  //Standard getters & setters for name, age, salary and leaves go here

  //Standard equals() & hashcode() methods go here
}
 OUTPUT of the above code
Average age using Collectors.averagingInt: 41.2
Average leaves using Collectors.averagingLong: 293.6
Average salary using Collectors.averagingDouble: 9800.0
Explanation of the code

  • AveragingWithCollectors class contains a static list of Employee objects – employeeList.
  • a stream of Employee objects is created using List.stream() method.
  • Stream of employees is pipelinedClick to Read Tutorial explaining Concept of Pipelines in Computing to the collect() terminal operationClick to Read Tutorial explaining intermediate & terminal Stream operations.
  • The code for 3 averaging collectors is same until this point. From here it proceeds slightly different for the three –
    • Collectors.averagingInt Collector
      • Collector returned by Collectors.averagingInt() method is passed as a parameter to the Stream.collect() method.
      • averagingInt collector takes ToIntFunction instance as an input which in this case is specified using the method reference
        Click to Read Tutorial on Java 8’s Method References
        to the Employee’s age passed as the sort key using – “Employee::getAge”.
      • The average age of all employees is then correctly printed as 41.2.
    • Collectors.averagingLong collector
      • Collector returned by Collectors.averagingLong() method is passed as a parameter to the Stream.collect() method.
      • averagingLong collector takes ToLongFunction instance as an input which in this case is specified using the method reference to the Employee’s leaves passed as the sort key using – “Employee::getLeaves”.
      • The average leaves of all employees is then correctly printed as 293.6.
    • Collectors.averagingDouble collector
      • Collector returned by Collectors.averagingDouble() method is passed as a parameter to the Stream.collect() method.
      • averagingDouble collector takes ToDoubleFunction instance as an input which in this case is specified using the method reference to the Employee’s leaves passed as the sort key using – “Employee::getSalary”.
      • The average salary of all employees is then correctly printed as 9800.0.

 

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