引入Java流的主要动机之一是允许并行操作。 这就导致了对Java流(例如map和filter)的操作必须独立于流中的项目位置或其周围的项目。 这具有易于分割流以进行并行处理的优点。 它具有使某些操作更复杂的缺点。
因此,简单的答案是,没有简单的方法可以完成诸如第n个项目或将每个项目映射到所有先前项目之和的操作。
实现要求的最直接方法是使用要从中流式传输的列表的索引:
List list = ...;
return IntStream.range(0, list.size())
.filter(n -> n % 3 == 0)
.mapToObj(list::get)
.collect(Collectors.toList());
一个更复杂的解决方案是创建一个自定义收集器,将第n个项目收集到一个列表中。
class EveryNth {
private final int nth;
private final List> lists = new ArrayList<>();
private int next = 0;
private EveryNth(int nth) {
this.nth = nth;
IntStream.range(0, nth).forEach(i -> lists.add(new ArrayList<>()));
}
private void accept(C item) {
lists.get(next++ % nth).add(item);
}
private EveryNth combine(EveryNth other) {
other.lists.forEach(l -> lists.get(next++ % nth).addAll(l));
next += other.next;
return this;
}
private List getResult() {
return lists.get(0);
}
public static Collector> collector(int nth) {
return Collector.of(() -> new EveryNth(nth),
EveryNth::accept, EveryNth::combine, EveryNth::getResult));
}
可以这样使用:
List list = Arrays.asList("Anne", "Bill", "Chris", "Dean", "Eve", "Fred", "George");
list.stream().parallel().collect(EveryNth.collector(3)).forEach(System.out::println);
它将返回您期望的结果。
即使是并行处理,这也是一种效率很低的算法。 它将接受的所有项目拆分为n个列表,然后仅返回第一个。 不幸的是,它必须保留所有项目的累积过程,因为直到它们组合起来才知道哪个列表是第n个。 鉴于其复杂性和效率低下,我绝对会建议优先使用上述基于索引的解决方案。