为什么Java的Iterator和ListIterator指向元素之间?


9

ListIteratorJavadoc说:

A ListIterator没有当前元素;它的光标位置始终位于调用返回previous()的元素和调用返回的元素之间next()

为什么Java的ListIterator实现指向元素之间而不是当前元素?看来,这使得客户端代码的可读性,当它必须反复调用getNext()getPrevious(),所以我认为必须有一个很好的理由选择。

作为一个方面说明,我只是写了一个小图书馆称为peekable-ArrayList的扩展ArrayListIterator以及ListIterator提供一个peekAtNext()peekAtPrevious()类似的方法来实现:

  @Override public synchronized T peekAtNext() {
     T t = next();
     previous();
     return t;
  }


谢谢凯文!我在SO上对此发布了一个后续问题:是否可以将Guava的ForwardingListIterator与PeekingIterator一起使用?
glenviewjeff 2012年

Answers:


12

据我所知,原因可以在您未引用的javadoc部分中找到(重点在我的下方):

列表的迭代器,允许程序员在任一方向上遍历列表,并在迭代过程中修改列表...

您会看到,其预期目的是允许在修改列表时使用。可能的修改显然包括删除元素。

现在考虑一下如果删除一个current()用于迭代器的元素会发生什么—假设迭代器具有当前元素的概念?在这种情况下,在没有当前元素概念的情况下实现它的方法对我来说非常有意义-因为那样,迭代器不必担心元素删除的问题。


重要的是要注意,javadoc不需要接口实现是线程安全的。

  • 因此,不应期望正确处理来自不同线程的修改 -为此,实现将必须提供其他方式来同步访问,保证可见性等,如Java内存模型根据JSR 133所指定的。

ListIterator的功能是在迭代时处理从同一线程完成的修改。并非所有的迭代器都那样,ConcurrentModificationException javadocs特别警告了这一点:

...请注意,此异常并不总是表示对象已由其他线程同时修改。如果单个线程发出违反对象约定的方法调用序列,则该对象可能会抛出此异常。例如,如果线程在使用快速失败迭代器迭代集合时直接修改集合,则迭代器将抛出此异常...


1
这也意味着您不需要单独的insertBefore并且insertAfter,尽管这不像remove
Karl Bielefeldt 2012年

1
那么,是否可以同时删除和访问当前元素的问题呢?这不是并发调用的等效问题next()吗? remove()synchronized一样getCurrent()。我想念什么吗?
glenviewjeff 2012年

@glenviewjeff这是一个非常好的观察。我还想知道如何在该处处理CME-明确指出的允许修改的意图引起了这样的担忧。猜猜我需要更深入地研究。我99.99%地肯定它不是打算作为线程安全的,也许它只能处理在同一个线程(不是所有的迭代器都能够,你知道)完成并发器官功能障碍综合征
蚊蚋

如果您有兴趣,请参阅我的编辑。我实现并打包了扩展ArrayList以完成此任务。
glenviewjeff 2012年

@glenviewjeff有趣。在您的实现中,next()和previous()是否也已同步?我问,因为如果没有,那么其他线程可以“钻”一些意外的动作到您current()的中间,使其表现得不像客户端期望的那样……add()之类的方法也可能需要同步
gna
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.