Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java streams: straightforward reduce

I've a stream of MetricGroup, where:

public class MetricGroup {

    private int uploadedDocs;
    private long uploadedKbs;

    // getters and setters

}

I need to sumarize all metrics in one single metric. I mean, I need to add all metric.uploadedDocs into a sumMetric.uploadedDocs and metric.uploadedKds into a sumMetric.uploadedKbs.

I figure out I need some kind of reduce

Stream.of(new MetricGroup(1,100), new MetricGroup(1,200))
    .reduce(????);

Any ideas?

like image 683
Jordi Avatar asked Jan 08 '19 10:01

Jordi


People also ask

What does reduce do in Java streams?

Reducing is the repeated process of combining all elements. reduce operation applies a binary operator to each element in the stream where the first argument to the operator is the return value of the previous application and second argument is the current stream element.

What is reduce in Java 8 streams?

A reduction is a terminal operation that aggregates a stream into a type or a primitive. The Java 8 Stream API contains a set of predefined reduction operations, such as average , sum , min , max , and count , which return one value by combining the elements of a stream.

What are the advantages of Java streams?

There are a lot of benefits to using streams in Java, such as the ability to write functions at a more abstract level which can reduce code bugs, compact functions into fewer and more readable lines of code, and the ease they offer for parallelization.

What is the use of reduce method of stream API?

The Stream API provides a rich repertoire of intermediate, reduction and terminal functions, which also support parallelization. More specifically, reduction stream operations allow us to produce one single result from a sequence of elements, by repeatedly applying a combining operation to the elements in the sequence.


2 Answers

You can use this overload of reduce:

T reduce(T identity,
     BinaryOperator<T> accumulator)

like this:

.reduce(new MetricGroup(0, 0),
        (x, y) -> new MetricGroup(
                      x.getUploadedDocs() + y.getUploadedDocs()
                      x.getUploadedKbs() + y.getUploadedKbs()
                  )
        )

You can also use the collect method:

private static MetricGroup combine(MetricGroup x, MetricGroup y) {
    x.setUploadedDocs(x.getUploadedDocs() + y.getUploadedDocs());
    x.setUploadedKbs(x.getUploadedKbs() + y.getUploadedKbs());
    return x;
}

// ....

.collect(() -> new MetricGroup(0, 0),
    YourClass::combine,
    YourClass::combine
)
like image 110
Sweeper Avatar answered Oct 30 '22 06:10

Sweeper


To avoid the creation of several/many MetricGroup objects during the reduce call, you can make two separate calls to sum the UploadedDocs and UploadedKbs respectively and then construct a new MetricGroup representing the result.

int uploadedDocsSum = source.stream().mapToInt(MetricGroup::getUploadedDocs).sum();
long uploadedKbsSum = source.stream().mapToLong(MetricGroup::getUploadedKbs).sum();
MetricGroup result = new MetricGroup(uploadedDocsSum, uploadedKbsSum);

Arguably more readable as well...

like image 28
Ousmane D. Avatar answered Oct 30 '22 06:10

Ousmane D.