Java Lambda重用Stream

时间:2014-06-23 17:46:36

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

我想尝试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:stream已经被操作或关闭

有了这些信息,我当然开了两个流并过滤了两次

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

但我现在的问题是关于表现。如果我必须过滤并映射两次流,那么这不是很慢。为什么我不能在流上操作多次,我不明白为什么他们这样实现它。 在操作之后不可能打开流,因为每个操作符方法都返回一个新流或单个值。

这是什么原因,或者我只是错误使用它?

2 个答案:

答案 0 :(得分:8)

如果你用旧的方式做到了,通过使用循环,你可以使用单个循环计算最大元素和平均值。所以你只需要在这里做同样的事情。幸运的是,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可以帮助您了解如何自己实现这样的操作。

答案 1 :(得分:3)

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

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