从流中获取最后n个元素

我想知道是否有替代方案

List lastN = all.subList(Math.max(0, all.size() - n), all.size()); 

使用

自定义收集器可以这样写:

 public static  Collector> lastN(int n) { return Collector., List>of(ArrayDeque::new, (acc, t) -> { if(acc.size() == n) acc.pollFirst(); acc.add(t); }, (acc1, acc2) -> { while(acc2.size() < n && !acc1.isEmpty()) { acc2.addFirst(acc1.pollLast()); } return acc2; }, ArrayList::new); } 

并像这样使用它:

 List lastTen = input.stream().collect(lastN(10)); 

使用Stream.skip()

在丢弃流的前n个元素后,返回由此流的其余元素组成的流。 如果此流包含少于n个元素,则将返回空流。

 all.stream().skip(Math.max(0, all.size() - n)).forEach(doSomething); 

如果流的大小未知,则可能无法使用整个流并缓冲到目前为止遇到的最后n元素。 您可以使用某种deque或自动保持其最大大小的专用环缓冲区来执行此操作(有关某些实现,请参阅此相关问题 )。

 public static  List lastN(Stream stream, int n) { Deque result = new ArrayDeque<>(n); stream.forEachOrdered(x -> { if (result.size() == n) { result.pop(); } result.add(x); }); return new ArrayList<>(result); } 

所有这些操作( sizepopadd )都应该具有O(1)的复杂度,因此具有(未知)长度n的流的总体复杂度将是O(n)