Чому Iterator і ListIterator Java переходять між елементами?


9

Javadoc для ListIterator каже:

A ListIteratorне має поточного елемента; його курсорне положення завжди лежить між елементом, до якого буде повернуто виклик, previous()і елементом, до якого буде повернуто виклик next().

Чому Java була ListIteratorреалізована для вказівки між елементами, а не на поточному елементі? Здається , що це робить код клієнта менш читабельним , коли він повинен повторно дзвонити getNext(), getPrevious(), тому я вважаю , що має бути вагомі підстави для вибору.

В якості примітки, я просто написав мало - бібліотека під назвою peekable-ArrayList , який проходить ArrayList, Iteratorі ListIteratorщо забезпечує peekAtNext()і peekAtPrevious()методи реалізовані як:

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

2
Існує peekable итератор в бібліотеці гуави code.google.com/p/guava-libraries
Кевін Клайн

Дякую Кевін! Я опублікував додаткове запитання до цього питання на SO: Чи можна використовувати Guava's ForwardingListIterator з PeekingIterator?
glenviewjeff

Відповіді:


12

Наскільки я можу сказати, причину можна знайти в тій частині javadoc, яку ви не цитували (наголос нижче моєї):

Ітератор списків, що дозволяє програмісту перетинати список у будь-якому напрямку, змінювати список під час ітерації ...

Розумієте, призначена мета - дозволити використання під час зміни списку. Можливі модифікації, мабуть, включають видалення елементів.

Тепер подумайте, що буде, якщо ми видалимо елемент, який був би current()для ітератора - припускаючи, що ітератор мав би поняття про поточний елемент? У цьому контексті спосіб реалізувати його без поняття поточного елемента має для мене досить хороший сенс - адже таким чином ітератору не потрібно турбуватися про видалення елементів.


Це важливо відзначити , що Javadoc не вимагає реалізації інтерфейсу потокобезпечна.

  • Через це не слід сподіватися на правильне поводження з модифікаціями, виконаними з різних потоків - для цього реалізація повинна забезпечити додаткові засоби для синхронізації доступу, гарантування видимості тощо, як зазначено в Моделі пам'яті Java для JSR 133 .

На що здатний ListIterator, він обробляє модифікації, виконані з тієї ж нитки під час ітерації. Не всі ітератори подібні, javadocs ConcurrentModificationException спеціально попереджають про це:

... Зауважте, що цей виняток не завжди вказує на те, що об'єкт одночасно був змінений іншим потоком. Якщо один потік видає послідовність викликів методу, що порушує контракт об'єкта, об'єкт може викинути цей виняток. Наприклад, якщо потік змінює колекцію безпосередньо під час ітерації над колекцією за допомогою невдалого ітератора, ітератор викине цей виняток ...


1
Це також означає , що вам не потрібно окремо insertBeforeі insertAfter, незважаючи на те, що це не така велика проблема , як remove.
Карл Білефельдт

1
Тож питання, яке можна одночасно видалити та отримати доступ до поточного елемента? Хіба це не було б рівнозначним питанням, як одночасно викликає next()? remove()було б synchronizedяк би getCurrent(). Я щось пропускаю?
glenviewjeff

@glenviewjeff це дуже гарне спостереження. Мені також цікаво, як CME там може оброблятися - саме заявлений намір дозволити модифікації викликає подібні проблеми. Здогадайтесь, мені потрібно копати глибше. Я 99,99% впевнений, що це не є безпечним для потоків, можливо, він може обробляти лише одночасні моди, виконані з тієї ж нитки (не всі ітератори на це здатні, знаєте)
gnat

Якщо вам цікаво, дивіться мою редакцію. Я реалізував і упакував розширення, ArrayListщоб досягти цього.
glenviewjeff

@glenviewjeff цікаво. Чи у вашій реалізації також наступні () та попередні () також синхронізовані? Я прошу, бо якщо ні, то інша нитка може "просвердлити" якийсь несподіваний хід прямо в середину поточного (), змусивши його вести себе не зовсім так, як очікував клієнт ... Такі методи, як add (), ймовірно, також потребують синхронізації
гнат
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.