Problema com tipos primitivos:

Se os preços fossem int, seria possível usar mapToDouble(...).sum().

Com BigDecimal, isso não é possível diretamente.

Solução com reduce:

Usando expressão lambda:

.reduce((total, price) -> total.add(price))

Usando method reference (mais limpo):

.reduce(BigDecimal::add)

Tratando o retorno Optional:

.reduce(BigDecimal::add)
.ifPresent(System.out::println);

Forma alternativa com valor inicial:

  • Evita Optional, retorna diretamente BigDecimal.

.reduce(BigDecimal.ZERO, BigDecimal::add)

Exemplo: ReduceExamples.java

Somando os valores de todos os pagamentos (payments)

Estratégia com map e reduce em duas etapas:

1 Gerar Stream de subtotais (Stream):

payments.stream()
.map(p -> p.getProducts().stream()
.map(Product::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add))

2 Somar os subtotais:

.reduce(BigDecimal.ZERO, BigDecimal::add)

Alternativa com flatMap (mais limpa):

Criar um único Stream de todos os produtos:

payments.stream()
.flatMap(p -> p.getProducts().stream()
.map(Product::getPrice))

Explicação da função usada:

Function> mapper =
p -> p.getProducts().stream().map(Product::getPrice);

obs.: Necessário usar flatMap para evitar Stream>.

Somando todos os valores diretamente:

.reduce(BigDecimal.ZERO, BigDecimal::add)

Exemplo: PagamentosReduceExemplos .java