3

I'm trying to use the Java 8 Stream API mapToDouble method like so:

BigDecimal totalCost = order.getOrderlineList().stream()
    .mapToDouble(Orderline::getPrice)
    .sum();

The problem is that Orderline::getPrice returns a BigDecimal, not a Double. Hence the attempt above fails to compile (Bad return type in method reference: cannot convert java.math.BigDecimal to doubele).

Seeing that Orderline#price is a BigDecimal, how can I use the Stream API (and either mapToDouble or something similar) to get my totalCost?

Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56
hotmeatballsoup
  • 385
  • 6
  • 58
  • 136

2 Answers2

5

You should add BigDecimals using BigDecimal.add() instead of converting them to double and back again to avoid rounding errors. To sum all prices you can use Stream.reduce():

BigDecimal bigDecimal = order.getOrderLines().stream()
        .map(OrderLine::getPrice)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

From the docs of Stream.reduce():

Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. This is equivalent to:

T result = identity;
for (T element : this stream)
    result = accumulator.apply(result, element)
return result;

BigDecimal::add is a short form of (a, b) -> a.add(b), which simply returns a + b. For addition the identity element is 0 or BigDecimal.ZERO.

Community
  • 1
  • 1
Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56
2

Using Eclipse Collections with Java Streams, this will work:

BigDecimal totalCost = order.getOrderlineList().stream()
    .collect(Collectors2.summingBigDecimal(Orderline::getPrice));

You can also use the Iterate class to simplify the code slightly.

BigDecimal totalCost = Iterate.sumOfBigDecimal(order.getOrderlineList(), Orderline::getPrice)

Note: I am a committer for Eclipse Collections

Donald Raab
  • 6,458
  • 2
  • 36
  • 44