【问题标题】:Java Lambda re-use StreamJava Lambda 复用 Stream
【发布时间】:2014-08-13 20:38:37
【问题描述】:

我想尝试 lambdas 的一些功能,并想编写一个 ArrayList 过滤器并使用 IntStream 的方法来计算一个数字 ArrayList 的平均值和最大值

我的第一个想法是过滤 ArrayList,保存流,然后使用方法计算:

ArrayList<Integer> arr = new ArrayList<>();
arr.add(5);
arr.add(7);
arr.add(11);

IntStream s = arr.stream().filter(i -> i < 10).mapToInt(i -> (int)i);
int maxBelowTen = s.max().getAsInt();
double avgBelowTen = s.average().getAsDouble();
System.out.println("Maximum below ten: " + maxBelowTen);
System.out.println("Average below ten: " + avgBelowTen);

但是,这会引发 java.lang.IllegalStateException:流已被操作或关闭

有了这些信息,我当然可以通过打开两个流并过滤两次来实现它

int maxBelowTen = arr.stream().filter(i -> i < 10).mapToInt(i -> (int) i).max().getAsInt();
double avgBelowTen = arr.stream().filter(i -> i < 10).mapToInt(i -> (int) i).average().getAsDouble();

但我现在的问题是关于性能。如果我必须两次过滤和映射流,那不是很慢。为什么我不能对流进行多次操作,我不明白他们为什么以这种方式实现它。 是否有可能在操作后让流保持打开状态,因为每个运算符方法都返回一个新流或单个值。

这是什么原因,还是我用错了?

【问题讨论】:

    标签: java collections lambda java-8 java-stream


    【解决方案1】:

    如果您使用旧方法,通过使用循环,您将使用单个循环计算最大元素和平均值。所以你只需要在这里做同样的事情。幸运的是,Stream API 可以为您完成:

    IntStream s = arr.stream().mapToInt(i -> Integer::intValue).filter(i < 10);
    IntSummaryStatistics stats = s.summaryStatistics();
    
    double average = stats.getAverage();
    int max = stats.getMax();
    

    阅读 IntSummaryStatistics 的 javadoc 应该可以帮助您了解如何自己实现这样的操作。

    【讨论】:

    • 哇,我不知道summaryStatistics()。考虑到所有其他被剥夺的功能,这到底是如何变得足够重要的呢? :-)
    【解决方案2】:

    如果你想“保存”中间流操作的结果,你可以这样做;您只需要明确地执行此操作:您必须执行 arr.stream().filter(i -&gt; i &lt; 10).mapToInt(i -&gt; (int) i).toArray(),存储 int[],然后对其执行操作。

    流不是数据结构,它们是尚未运行的待处理计算,并且可能以非标准方式将未来的操作合并在一起。如果您想将中间结果存储在适当的数据结构中,则必须自己完成。

    【讨论】:

      猜你喜欢
      • 2015-03-08
      • 1970-01-01
      • 2018-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-21
      相关资源
      最近更新 更多