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`.