descendingIterator为java.util.List
descendingIterator为java.util.List
LinkedList可以使用升序或降序迭代器进行迭代,如下所示:\n
LinkedList
\n
\n
averse: Hello 2 Chocolate 10 reverse: 10 Chocolate 2 Hello\n
\n但是List和ArrayList没有提供descendingIterator。\n是否有任何解决方法或至少解释一下,为什么List中没有descendingIterator?\n这个问题类似于Can one do a for each loop in java in reverse order?,但是所有的答案都推荐使用临时解决方案或第三方库。\n也许使用流stream是可能的吗?(不幸的是,我的谷歌搜索只给出了缺少标准反向流的情况Java 8 stream reverse order)\n正如我提到的,我的问题与流有关,但是:\n
- \n
- 使用流只是一种选择,问题涉及到java.util.Iterator和java.util.List
- 对于那个问题的答案只解决了部分情况,但是显示了方便的通用反向方法的缺失。如果我没有错过术语,List是有序集合,对Comparable项目进行排序,为了达到顺序减少了范围。
\n
\n
在Java的List接口中,为什么没有提供一个descendingIterator的解释是有原因的。遍历List的效率很大程度上取决于List的实现方式。在设计一个接口时,通常希望这个接口适用于任何可能的实现方式。Java的LinkedList是一个双向链表,意味着每个元素都链接到其前一个和后一个元素,因此可以编写高效的升序和降序遍历器。然而,如果使用的是单向链表,降序遍历会非常低效,每次迭代都需要遍历整个链表直到当前索引。我怀疑正是因为这个原因,语言设计者决定在List接口中省略了降序遍历器。对于ArrayList来说,可以使用基于索引的方法相对容易地实现一个高效的降序遍历器,而对于LinkedList来说,使用索引方法要比其首选实现方式慢得多。以下是一些降序遍历的示例代码:
for(int i=list.size() -1; i >= 0; i--){ System.out.println(list.get(i)); } IntStream.range(0, list.size()) .map(i-> list.size() - 1 - i) .mapToObj(list::get) .forEach(System.out::println);
Java的List接口没有提供descendingIterator方法的一个很好的原因。每个List都必须支持一个可以以相反顺序迭代的ListIterator,可以使用hasPrevious()和previous()方法。虽然这似乎是一个相当不常见的用例。
为了解决这个问题,可以使用一个小的实用程序方法将Iterable适配为以相反顺序迭代的ListIterator。可以使用如下代码实现:
staticIterable descendingIterable(List extends T> list) { return () -> { ListIterator extends T> li = list.listIterator(list.size()); return new Iterator () { public boolean hasNext() { return li.hasPrevious(); } public T next() { return li.previous(); } }; }; }
可以使用它来实现示例代码:
Listlist = Arrays.asList("Hello", "2", "Chocolate", "10"); StringJoiner sj = new StringJoiner(" "); descendingIterable(list).iterator().forEachRemaining(sj::add); System.out.println(sj);
或者可以在增强型for循环中使用它:
for (String s : descendingIterable(list)) { System.out.println(s); }
需要注意的是,如果List可能会在并发环境中被修改,存在一个小的问题。它发生在这段代码中:
list.listIterator(list.size())
如果这种情况可能发生,要么在List上使用外部同步,要么如果List是CopyOnWriteArrayList,则必须先进行克隆。关于后者的更多信息,请参见这个答案。