在Java 8流中避免NoSuchElementException

时间:2014-03-25 18:12:41

标签: java lambda java-8 java-stream

此问题是对早期问题的跟进:Adding up BigDecimals using Streams

与使用Java 8 BigDecimal和Lambda表达式添加Stream相关的问题。在实现给出的答案后,我遇到了另一个问题:每当流为空时,Optional::get()方法抛出NoSuchElementException

请考虑以下代码:

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());
}

vanilla Java代码对空集合没有问题,但新的Java 8代码可以。

在这里避免使用NSEE最优雅的方法是什么?我们当然可以做到:

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

但是有没有一种Java-8-ish方式来处理空集合?

2 个答案:

答案 0 :(得分:6)

在这种情况下,应该使用可以返回reduce的{​​{1}}版本。

你应该使用前面提到的另一个版本,它提供了一个标识元素,以防流是空的,这就是identity元素存在的全部原因。

所以你想拥有:

Optional<BigDecimal>

而不是旧版本。

在这种情况下,您不关心流是否为空,您只需要一个有效的结果。

答案 1 :(得分:5)

在输入示例来提问时,我找到了答案:

Stream::reduce()返回Optional,其中包含orElse()方法。所以,

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

变为

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

所以我决定发布一个Q-and-A。

Lambdas很棒。 +1 Java。