Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding NoSuchElementException in Java 8 streams

This question is a follow-up to an earlier question: Adding up BigDecimals using Streams

The question related to adding up BigDecimals using Java 8 Streams and Lambda expressions. After implementing the answers given, I ran into another problem: whenever the stream is empty, the Optional::get() method throws a NoSuchElementException.

Consider the following code:

public static void main(String[] args){
    LinkedList<BigDecimal> values = new LinkedList<>();
//        values.add(BigDecimal.valueOf(.1));
//        values.add(BigDecimal.valueOf(1.1));
//        values.add(BigDecimal.valueOf(2.1));
//        values.add(BigDecimal.valueOf(.1));

    // Classical Java approach
    BigDecimal sum = BigDecimal.ZERO;
    for(BigDecimal value : values) {
        System.out.println(value);
        sum = sum.add(value);
    }
    System.out.println("Sum = " + sum);

    // Java 8 approach
    values.forEach((value) -> System.out.println(value));
    System.out.println("Sum = " + values.stream().reduce((x, y) -> x.add(y)).get());
}

The vanilla Java code has no problem with an empty collection, but the new Java 8 code does.

What is the most elegant way to avoid a NSEE here? Certainly we could do:

System.out.println("Sum = " + values == null || values.isEmpty() ? 0 : values.stream().reduce((x, y) -> x.add(y)).get());

But is there a Java-8-ish way to handle empty collections?

like image 327
ryvantage Avatar asked Dec 04 '25 11:12

ryvantage


2 Answers

You should, in this case, not be using the version of reduce that can return an Optional<BigDecimal>.

You should be using the other version, as mentioned before, that provides an identity element in case the stream is empty, that is the whole reason the identity element is there.

So you want to have:

System.out.println("Sum = " + values.stream().reduce(BigDecimal.ZERO, (x, y) -> x.add(y));

Instead of the old version.

In this case you do not care about whether the stream is empty or not, you just want a valid result.

like image 93
skiwi Avatar answered Dec 05 '25 23:12

skiwi


While typing the example to ask the question, I found the answer:

Stream::reduce() returns an Optional which has a method: orElse(). So,

System.out.println("Sum = " + values.stream().reduce((x, y) -> x.add(y)).get());

becomes

System.out.println("Sum = " + values.stream().reduce((x, y) -> x.add(y)).orElse(BigDecimal.ZERO));

So I decided to post a Q-and-A.

Lambdas are great. +1 Java.

like image 23
ryvantage Avatar answered Dec 05 '25 23:12

ryvantage



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!