避免Java8流中的NoSuchElementException

避免Java8流中的NoSuchElementException,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,此问题是先前问题的后续问题: 这个问题与使用Java8Streams和Lambda表达式将BigDecimals相加有关。在实现了给出的答案之后,我遇到了另一个问题:每当流为空时,Optional::get()方法就会抛出一个NoSuchElementException 考虑以下代码: public static void main(String[] args){ LinkedList<BigDecimal> values = new LinkedList<>()

此问题是先前问题的后续问题:

这个问题与使用Java8
Stream
s和Lambda表达式将
BigDecimal
s相加有关。在实现了给出的答案之后,我遇到了另一个问题:每当流为空时,
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());
}

但是有没有Java-8-ish方法来处理空集合呢?

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

Stream::reduce()
返回一个
可选的
,它有一个方法:
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));
所以我决定发布一个问答

兰姆达斯很棒+1 Java。

在这种情况下,您不应该使用可返回
可选
reduce
版本

如前所述,您应该使用另一个版本,该版本在流为空时提供标识元素,这就是标识元素存在的全部原因

所以你想要:

System.out.println("Sum = " + values.stream().reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
而不是旧版本


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

您是否查看了另一个答案,它使用重载的
reduce()
方法,将
bigdecim.ZERO
作为第一个参数传递?该方法只返回一个
BigDecimal
,而不是
Optional
。错误在于对一个您不知道其值为非空的可选值调用get()。相反,使用条件方法之一,如orElse()或ifPresent(),或基于可选的.isPresent()编写条件代码。嗯,这就是标识值存在的原因?当流不为null时,标识值是否起作用?
Stream
类提供的无数选项可能会令人困惑。@ryvantage标识值相当于您的
BigDecimal sum=BigDecimal.ZERO在Java 7代码中的for循环之前。是的,两个arg
reduce
表单(带有标识值)在这里是合适的。标识值不仅在零元素流的情况下使用,而且在执行并行缩减时还用作部分结果的初始值。顺序相反:values.stream().reduce((x,y)->x.add(y)).ifPresent(s->System.out.println(“sum=“+s));//仅当总和有值时才打印。
System.out.println("Sum = " + values.stream().reduce(BigDecimal.ZERO, (x, y) -> x.add(y));