Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java8 stream sum multiple

I am curious, how to sum up multiple variables in a java8 stream.

Integer wCPU = 0;
Double wnetwork = 0.0;
Double wMem = 0.0;

this.slaContractList.forEach(sla -> {
    wCPU += sla.getNumberOfCPUs();
    wnetwork += sla.getNetworkBandwith();
    wMem += sla.getMemory();
});

However, this does not compile as the variable in the lambda expression should be final.

like image 424
Georg Heiler Avatar asked Nov 12 '16 21:11

Georg Heiler


3 Answers

Try to use Stream.reduce and Stream.sum:

Double wnetwork = slaContractList.stream()
            .mapToDouble(sla -> sla.getNetworkBandwith())
            .sum();

Double wMem = slaContractList.stream()
            .mapToDouble(sla -> sla.getMemory())
            .sum();

Integer wCPU = slaContractList.stream()
            .mapToInt(sla -> sla.getNumberOfCPUs())
            .sum();

See https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html

The advantage of using stream is option of use parallelStream() instead of stream(). In some situations it can be more efficient than simple loop.

like image 103
Łukasz Avatar answered Oct 22 '22 08:10

Łukasz


Just to do a sum, i would use the sum operation of streams just like in Łukasz answer, but, for a more general solution for resolving the "final problem" you can use the classes of java.util.concurrent.atomic. It is intented to be used in stream and is thread-safe, so could be used in a parallel stream.

AtomicInteger wCPU = new AtomicInteger();
DoubleAccumulator wnetwork = new DoubleAccumulator(Double::sum,0.d);
DoubleAccumulator wMem = new DoubleAccumulator(Double::sum,0.d);

this.slaContractList.forEach(sla -> {
    wCPU.addAndGet(sla.getNumberOfCPUs());
    wnetwork.accumulate(sla.getNetworkBandwith());
    wMem.accumulate(sla.getMemory());
});

Now you see that there are 2 kind of implementation: the Accumulator and the Atomic, the choice between these 2 is another question:

java 8 : Are LongAdder and LongAccumulator preferred to AtomicLong?

like image 3
pdem Avatar answered Oct 22 '22 09:10

pdem


I would do a simple hack like this:

    Integer[] wCPU = new Integer[1];
    Double[] wnetwork = new Double[1];
    Double[] wMem = new Double[1];

    this.slaContractList.forEach(sla -> {
        wCPU[0] += sla.getNumberOfCPUs();
        wnetwork[0] += sla.getNetworkBandwith();
        wMem[0] += sla.getMemory();
    });

It's optional to have the final keyword for both , as in Java 8 they have introduced the effectively final concept. It means, you have assigned only once.

like image 2
Jude Niroshan Avatar answered Oct 22 '22 09:10

Jude Niroshan