引入Java流的主要动机之一是允许并行操作。这导致要求对诸如地图和过滤器之类的Java流的操作独立于流中的项目的位置或其周围的项目。这具有使流易于分流以进行并行处理的优点。它具有使某些操作更复杂的缺点。
所以简单的答案是,没有一个简单的方法来做这些事情,例如把每个第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个。鉴于其复杂性和效率低下,我一定会建议坚持使用上述基于索引的解决方案。