【问题标题】:Avoiding NoSuchElementException in Java 8 streams在 Java 8 流中避免 NoSuchElementException
【发布时间】:2014-05-03 18:58:29
【问题描述】:

这个问题是对先前问题的后续问题:Adding up BigDecimals using Streams

与使用 Java 8 Streams 和 Lambda 表达式相加 BigDecimals 相关的问题。在执行给出的答案后,我遇到了另一个问题:每当流为空时,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 代码对空集合没有问题,但新的 Java 8 代码可以。

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

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

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

【问题讨论】:

  • 颠倒顺序:values.stream().reduce((x, y) -> x.add(y)).ifPresent(s -> System.out.println("sum = " + s)); // 只有当它有值时才打印总和。

标签: java lambda java-8 java-stream


【解决方案1】:

在这种情况下,您应该使用可以返回Optional&lt;BigDecimal&gt;reduce 版本。

您应该使用其他版本,如前所述,在流为空的情况下提供标识元素,这就是标识元素存在的全部原因。

所以你想拥有:

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

而不是旧版本。

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

【讨论】:

  • 嗯,这就是身份值存在的原因?当流不为空时,标识值是否有任何作用? Stream 类提供的无数选项可能会令人困惑。
  • @ryvantage 在 Java 7 代码中的 for 循环之前,标识值等同于 BigDecimal sum = BigDecimal.ZERO;
  • 是的,两个参数的reduce 形式(带有标识值)在这里是合适的。标识值不仅在零元素流的情况下使用,在做并行归约时也可以作为部分结果的初始值。
【解决方案2】:

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

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

所以我决定发布一个问答。

Lambda 很棒。 +1 Java。

【讨论】:

  • 您是否看过另一个答案,它使用重载的reduce() 方法,将BigDecimal.ZERO 作为第一个参数传递?该方法仅返回BigDecimal,而不是Optional
  • 错误是在一个你不知道它是非空的可选对象上调用 get()。相反,使用其中一种条件方法,如 orElse() 或 ifPresent(),或基于 Optional.isPresent() 编写条件代码。
猜你喜欢
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 2016-11-27
  • 2020-12-07
  • 2021-04-22
  • 1970-01-01
  • 2021-11-15
相关资源
最近更新 更多