如何在Java 8中以相反的顺序从列表中获取有序流

是否有一种理智的方式从列表中获取有序流(具体来说,数组列表,但它应该无关紧要)流式元素与它们在原始列表中的方式相反?

我正在寻找一种不涉及缓冲数据的解决方案(收集器,另一个列表,数组等,因为它们复制了浪费的容器),或者使用Collections.reverse (因为它修改了列表)。

到目前为止,我在这里看到的最Spliterator的方法是实现我自己的Spliterator版本,它是ORDERED并反向推进列表,或者实现反向Iterator ,并在其上使用Spliterators.spliteratorUnknownSize(iterator,ORDERED)

注意这个问题与Java 8流逆向顺序不同 :其他问题询问如何反转流(一般情况下这是不可能的),并且答案提供了以某种方式反转源(我不想这样做),然后传输反向源。 逆转源的成本是O(N),如果可能的话我想完全避免它。

如果您的List是随机访问列表,您可以使用

 int num=list.size()-1; IntStream.rangeClosed(0, num).mapToObj(i->list.get(num-i)) 

创建具有ORDERED | SIZED | SUBSIZED特征的Stream ORDERED | SIZED | SUBSIZED ORDERED | SIZED | SUBSIZED并提供完全分裂支持。

对于像LinkedList这样的非随机访问列表,它会是一个性能灾难,但是,谁还使用LinkedList

您也可以先通过list instanceof RandomAccess查看…

注意:如果您有一个ArrayList或其他列表允许通过索引( get(i) )进行随机访问检索,那么Holger的方法更可取。 只有当您的数据结构允许反向遍历但不允许索引访问时,才需要使用下面的方法。


不幸的是,似乎没有一种非常简单的方法(即单线程)来做到这一点。 但是,使用AbstractSpliterator获取反向流并不太困难,因为List已经具有反向迭代的能力。 这是一个实用方法:

 static  Stream reversedStream(List input) { ListIterator li = input.listIterator(input.size()); return StreamSupport.stream( new Spliterators.AbstractSpliterator(input.size(), Spliterator.ORDERED) { @Override public boolean tryAdvance(Consumer action) { if (li.hasPrevious()) { action.accept(li.previous()); return true; } else { return false; } } }, false); } 

(我认为Spliterator可能是SIZED ,但这大多没有意义,因为这是一个不可分割的分裂器 。)

就目前而言,这可以提供有限程度的并行性,因为AbstractSpliterator将多次调用tryAdvance并批量处理以交付fork-join任务。 但它没有能够分裂的效率。

如果并行效率是一个很大的问题,那么可以编写一个可以实际拆分的分裂器,其中拆分以相反的顺序遍历。

我倾向于喜欢@ teppic使用第三方库来做到这一点的答案。 但是,尝试仅使用Java 8 API提出解决方案是一项有趣的练习。 委托给ListIterator是我能想到的最干净的事情,但它并不比从头开始实现你自己的Iterator更干净。

 public static void main(String[] args){ List l = Arrays.asList("first", "second", "third"); StreamSupport.stream(Spliterators.spliterator(revit(l), l.size(), 0), false) .forEachOrdered(System.out::println); } private static final  Iterator revit(List l){ ListIterator li = l.listIterator(l.size()); return new Iterator(){ @Override public boolean hasNext(){ return li.hasPrevious(); } @Override public T next(){ return li.previous(); } }; } 

Google的Guava库提供了列表的反向视图( Lists#reverse(List) )。 Apache Commons Collection库中也有一个ReverseListIterator