Foreach with lambda which returns the sum of iterated items

Asked

Viewed 1,284 times

2

I’m trying to iterate on a List calling for produtos of objects called Produto, using the forEach, to obtain the sum of the values of these products using the lambda function of the forEach. But I can’t find the right syntax to do it.

Look at my code:

    private double getValorVenda(){
       double valor=0;

        produtos.forEach(produto -> {
            produto.getValor(Venda.class);
        });
        return valor;
    }
}

Any idea?

2 answers

7


Why not use a for simple?

private double getValorVenda() {
    double valor = 0.0;
    for (Produto produto : produtos) {
        valor += produto.getValor(Venda.class);
    }
    return valor;
}

The method forEach serves to "do something" with each element of the list, so much that it takes as parameter one Consumer (an operation that does something with the element and returns nothing).

If you try to do the same algorithm above with forEach, the code does not compile:

produtos.forEach(p -> {
    valor += p.getValor(Venda.class);
});

This code gives a build error:

local variables referenced from a lambda Expression must be final or effectively final

This happens because variables declared outside a lambda can only be used within it if they are final. But if I declare it as final:

final double valor = 0.0;

Then I can’t modify it, and the code makes another mistake:

cannot assign a value to final variable value

Anyway, if you want to summarize results, a loop traditional already resolves.


But if you want, you can use streams, an alternative is to do so:

double valor = produtos
    // cria o stream
    .stream()
    // obtém os valores das vendas de todos os produtos
    .mapToDouble(produto -> produto.getValor(Venda.class))
    // soma tudo
    .sum();

Thereby, valor shall have the sum of the values, or zero if the list of products is empty.

Just remembering that streams are legal, but have their cost and generally will be slower than a loop traditional, and we have to balance the clarity of the code and other benefits that the streams bring (goes of the opinion of each one) versus the speed. Of course, for simple cases like this it may not make much difference, but it’s something to always consider.

  • 1

    It makes sense. I’m sorry it took so long, I put it aside for a few weeks.

1

Lucas.

I do not know if the foreach is a good option to add value, and also I could not do using it.

What I normally use is to return a stream, use a map to get the values and a reduce later, to add it all up:

double valor = lista.stream().map(x -> x.getValor()).reduce((x,y) -> x + y).orElse(0.0);

Since I’m no expert on Java 8, you probably have more efficient ways.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.