descendingIterator为java.util.List

18 浏览
0 Comments

descendingIterator为java.util.List

LinkedList可以使用升序或降序迭代器进行迭代,如下所示:\n

LinkedList list = new LinkedList();
   ...
StringJoiner sJ1 = new StringJoiner(" ");
list.iterator().forEachRemaining(a -> sJ1.add(a.toString()));
System.out.println("averse: \n" + sJ1.toString());
StringJoiner sJ2 = new StringJoiner(" ");
list.descendingIterator().forEachRemaining(a -> sJ2.add(a.toString()));
System.out.println("reverse: \n" + sJ2.toString());

\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.Iteratorjava.util.List
  • \n

  • 对于那个问题的答案只解决了部分情况,但是显示了方便的通用反向方法的缺失。如果我没有错过术语,List是有序集合,对Comparable项目进行排序,为了达到顺序减少了范围。
  • \n

0
0 Comments

在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);

0
0 Comments

Java的List接口没有提供descendingIterator方法的一个很好的原因。每个List都必须支持一个可以以相反顺序迭代的ListIterator,可以使用hasPrevious()和previous()方法。虽然这似乎是一个相当不常见的用例。

为了解决这个问题,可以使用一个小的实用程序方法将Iterable适配为以相反顺序迭代的ListIterator。可以使用如下代码实现:

static  Iterable descendingIterable(List list) {
    return () -> {
        ListIterator li = list.listIterator(list.size());
        return new Iterator() {
            public boolean hasNext() { return li.hasPrevious(); }
            public T next() { return li.previous(); }
        };
    };
}

可以使用它来实现示例代码:

List list = 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,则必须先进行克隆。关于后者的更多信息,请参见这个答案

0