Averaging

Another common statistics to calculate is the average of values, defined as the sum of values divided by the number of values. A loop-based solution to calculate the average would explicitly sum the values, count the number of values, and do the calculation. In a stream-based solution, the average() terminal operation can be used to calculate this value. The stream pipeline below computes the average number of tracks on a CD. The CD stream is mapped to an int stream whose values are the number of tracks on a CD. The average() terminal operation adds the number of tracks and counts the values, returning the average as a double value encapsulated in an OptionalDouble.

Click here to view code image

OptionalDouble optAverage = CD.cdList
    .stream()
    .mapToInt(CD::noOfTracks)
    .average();
System.out.println(optAverage.orElse(0.0));        // 8.4

The reason for using an Optional is that the average is not defined if there are no values. The absence of a value in the OptionalDouble returned by the method means that the stream was empty.

Summarizing

The result of a functional reduction is a single value. This means that for calculating different results—for example, count, sum, average, min, and max—requires separate reduction operations on a stream.

The method summaryStatistics() does several common reductions on a stream in a single operation and returns the results in an object of type NumTypeSummaryStatistics, where NumType is Int, Long, or Double. An object of this class encapsulates the count, sum, average, min, and max values of a stream.

The classes IntSummaryStatistics, LongSummaryStatistics, and DoubleSummaryStatistics in the java.util package define the following constructor and methods, where NumType is Int (but it is Integer when used as a type name), Long, or Double, and the corresponding numtype is int, long, or double:

NumType
SummaryStatistics()

Creates an empty instance with zero count, zero sum, a min value as Num-Type.MAX_VALUE, a max value as NumType.MIN_VALUE, and an average value of zero.

double getAverage()

Returns the arithmetic mean of values recorded, or zero if no values have been recorded.

long getCount()

Returns the count of values recorded.

numtype
 getMax()

Returns the maximum value recorded, or NumType.MIN_VALUE if no values have been recorded.

numtype
 getMin()

Returns the minimum value recorded, or NumType.MAX_VALUE if no values have been recorded.

numtype
 getSum()

Returns the sum of values recorded, or zero if no values have been recorded. The method in the IntSummaryStatistics and LongSummaryStatistics classes returns a long value. The method in the DoubleSummaryStatistics class returns a double value.

void accept(
numtype
 value)

Records a new value into the summary information, and updates the various statistics. The method in the LongSummaryStatistics class is overloaded and can accept an int value as well.

Click here to view code image

void combine(
NumType
SummaryStatistics other)

Combines the state of another NumTypeSummaryStatistics into this one.

The summaryStatistics() method is used to calculate various statistics for the number of tracks on two CDs processed by the stream pipeline below. Various get methods are called on the IntSummaryStatistics object returned by the summary-Statistics() method, and the statistics are printed.

Click here to view code image

IntSummaryStatistics stats1 = List.of(CD.cd0, CD.cd1)
    .stream()
    .mapToInt(CD::noOfTracks)
    .summaryStatistics();
System.out.println(“Count=”   + stats1.getCount());        // Count=2
System.out.println(“Sum=”     + stats1.getSum());          // Sum=14
System.out.println(“Min=”     + stats1.getMin());          // Min=6
System.out.println(“Max=”     + stats1.getMax());          // Max=8
System.out.println(“Average=” + stats1.getAverage());      // Average=7.0

The default format of the statistics printed by the toString() method of the IntSummaryStatistics class is shown below:

Click here to view code image

System.out.println(stats1);
//IntSummaryStatistics{count=2, sum=14, min=6, average=7.000000, max=8}

Below, the accept() method records the value 10 (the number of tracks on CD.cd2) into the summary information referenced by stats1. The resulting statistics show the new count is 3 (=2 +1), the new sum is 24 (=14+10), and the new average is 8.0 (=24.0/3.0). However, the min value was not affected but the max value has changed to 10.

Click here to view code image

stats1.accept(CD.cd2.noOfTracks());     // Add the value 10.
System.out.println(stats1);
//IntSummaryStatistics{count=3, sum=24, min=6, average=8.000000, max=10}

The code below creates another IntSummaryStatistics object that summarizes the statistics from two other CDs.

Click here to view code image

IntSummaryStatistics stats2 = List.of(CD.cd3, CD.cd4)
    .stream()
    .mapToInt(CD::noOfTracks)
    .summaryStatistics();
System.out.println(stats2);
//IntSummaryStatistics{count=2, sum=18, min=8, average=9.000000, max=10}

The combine() method incorporates the state of one IntSummaryStatistics object into another IntSummaryStatistics object. In the code below, the state of the IntSummary-Statistics object referenced by stats2 is combined with the state of the IntSummary-Statistics object referenced by stats1. The resulting summary information is printed, showing that the new count is 5 (=3 +2), the new sum is 42 (=24+18), and the new average is 8.4 (=42.0/5.0). However, the min and max values were not affected.

Click here to view code image

stats1.combine(stats2);                 // Combine stats2 with stats1.
System.out.println(stats1);
//IntSummaryStatistics{count=5, sum=42, min=6, average=8.400000, max=10}

Calling the summaryStatistics() method on an empty stream returns an instance of the IntSummaryStatistics class with a zero value set for all statistics, except for the min and max values, which are set to Integer.MAX_VALUE and Integer.MIN_VALUE, respectively. The IntSummaryStatistics class provides a zero-argument constructor that also returns an empty instance.

Click here to view code image

IntSummaryStatistics emptyStats = IntStream.empty().summaryStatistics();
System.out.println(emptyStats);
//IntSummaryStatistics{count=0, sum=0, min=2147483647, average=0.000000,
//max=-2147483648}

The summary statistics classes are not exclusive for use with streams, as they provide a constructor and appropriate methods to incorporate numeric values in order to calculate common statistics, as we have seen here. We will return to calculating statistics when we discuss built-in collectors (p. 978).

Leave a Reply

Your email address will not be published. Required fields are marked *