java.util.Stream reduce

The Stream.reduce performs a reduction on the elements of the stream returning OptionalDouble. The operation allows you to combine elements of a stream to express complicated queries such as "calculate the total precipication for the year" or "when did the most precipication occur".

Similar to the examples below, a new java 8 class DoubleSummaryStatistics also collects statistics such as count, min, max, sum, and average. If you are looking at working with int use IntSummaryStatistics or long use LongSummaryStatistics.

Setup

class Precipitation {

    private LocalDate occurrence;
    private double amount;

    public Precipitation(LocalDate occurrence, double amount) {
        super();
        this.occurrence = occurrence;
        this.amount = amount;
    }
}

List<Precipitation> precip;

@Before
public void setUp() {

    precip = new ArrayList<>();

    precip.add(new Precipitation(LocalDate.of(2014, Month.JANUARY, 7), .25));
    precip.add(new Precipitation(LocalDate.of(2014, Month.FEBRUARY, 9), .10));
    precip.add(new Precipitation(LocalDate.of(2014, Month.FEBRUARY, 15),
            .50));
    precip.add(new Precipitation(LocalDate.of(2014, Month.MARCH, 9), 1.09));
}

sum

The example below will find the total amount (sum) of precipitation for the given stream. In the past while trying to calculate sum values in a list or summing values in array, the elements had to be combined iteratively. The stream.reduce approach is processed internally which makes for much cleaner code.

@Test
public void sum_elements() {

    double totalPrecipYear = precip.stream()
            .mapToDouble(Precipitation::getAmount).sum();

    assertEquals(1.9399999999999997, totalPrecipYear, 0);

    // or
    OptionalDouble totalPrecipYear2 = precip.stream()
            .mapToDouble(Precipitation::getAmount).reduce(Double::sum);

    assertEquals(1.94, totalPrecipYear2.getAsDouble(), 0);
    
    // or 
    double totalPrecipYear3 = precip.stream()
            .mapToDouble(Precipitation::getAmount).reduce(0, (a, b) -> a + b);
    
    assertEquals(1.94, totalPrecipYear3, 0);
}

max

Stream.max is another reduction operation which is processed internally and is similar to finding max value in array or max value from list. The example below will find the date with the highest precipitation.

@Test
public void max_elements() {

    OptionalDouble max = precip.stream()
            .mapToDouble(Precipitation::getAmount).max();

    assertEquals(1.09, max.getAsDouble(), 0);

    // or
    
    OptionalDouble max2 = precip.stream()
            .mapToDouble(Precipitation::getAmount).reduce(Double::max);

    assertEquals(1.09, max2.getAsDouble(), 0);
}

min

Just the opposite of max, Stream.min will find the minimum value in the stream. This operation is similar to finding the minimum value in an array or finding the minimum value in a collection but processed internally not iteratively. The example below will find the day with the lowest precipitation.

@Test
public void min_elements() {

    OptionalDouble min = precip.stream()
            .mapToDouble(Precipitation::getAmount).min();

    assertEquals(1.09, min.getAsDouble(), 0);

    // or
    
    OptionalDouble min2 = precip.stream()
            .mapToDouble(Precipitation::getAmount).reduce(Double::min);

    assertEquals(1.09, min2.getAsDouble(), 0);
}

average

Stream.average will calculate the average value of an Integer property of the items in the Stream. This operation similar to calculate average of values in array or calculate average of values in collection but processed internally not iteratively. The example below will find the avareage of preciptiation across all entries in the stream.

@Test
public void average_of_elements() {

    OptionalDouble average = precip.stream()
            .mapToDouble(Precipitation::getAmount).average();
    
    assertEquals(0.48499999999999993, average.getAsDouble(), 0);
}

count

Stream.count will count the number of elements in a stream. This operation is similar to counting elements in list. The example below will count the total number of elements in the precip stream.

@Test
public void count_elements() {

    long numberOfElements = precip.stream()
            .mapToDouble(Precipitation::getAmount).count();
    
    assertEquals(4.0, numberOfElements, 0);
}