Каковы преимущества интерфейса Iterator в Java?

Я только что узнал о том, как Java Collections Framework реализует структуры данных в связанных списках. Насколько я понимаю, Iterators - это способ обхода элементов в структуре данных, такой как список. Почему используется этот интерфейс? Почему методы hasNext(), next() и remove() не закодированы напрямую в самой реализации структуры данных?

С веб-сайта Java: текст ссылки

public interface Iterator<E>

An iterator over a collection. Iterator takes the place of Enumeration in the Java collections framework. Iterators differ from enumerations in two ways:

  • Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
  • Method names have been improved.
This interface is a member of the Java Collections Framework.

Я пробовал гуглить и не нашел однозначного ответа. Может ли кто-нибудь пролить свет на то, почему Sun решила их использовать? Это из-за лучшего дизайна? Повышенная безопасность? Хорошая практика ООП?

Любая помощь будет оценена. Спасибо.


person user17182    schedule 18.09.2008    source источник


Ответы (16)


Почему используется этот интерфейс?

Потому что он поддерживает основные операции, которые позволили бы клиентскому программисту перебирать любой набор (примечание: не обязательно Collection в смысле Object).

Почему методы... не закодированы напрямую в самой реализации структуры данных?

Они есть, они просто помечены как «Частные», чтобы вы не могли добраться до них и возиться с ними. Более конкретно:

  • Вы можете реализовать или подклассировать Iterator так, чтобы он делал то, чего не делают стандартные, без необходимости изменять фактический объект, по которому он выполняет итерацию.
  • Интерфейсы объектов, через которые можно пройти, не должны быть загромождены методами обхода, в частности любыми узкоспециализированными методами.
  • Вы можете раздать Iterators любому количеству клиентов, и каждый клиент может перемещаться в свое время и со своей скоростью.
  • Java Iterators из пакета java.util, в частности, вызовет исключение, если хранилище, поддерживающее их, будет изменено, пока у вас все еще есть Iterator. Это исключение сообщает вам, что теперь Iterator может возвращать недопустимые объекты.

Для простых программ ничего из этого, вероятно, не кажется целесообразным. Однако та сложность, которая делает их полезными, быстро придет к вам.

person Dustman    schedule 18.09.2008

Вы спросите: почему методы hasNext(), next() и remove() не закодированы напрямую в самой реализации структуры данных?

Платформа коллекций Java решает определить интерфейс Iterator как внешний по отношению к самой коллекции. Обычно, поскольку каждая коллекция Java реализует интерфейс Iterable, программа Java будет вызывать iterator для создания собственного итератора, чтобы его можно было использовать в цикле. Как указывали другие, Java 5 позволяет нам напрямую использовать итератор с циклом for-each.

Вынесение итератора на его коллекцию позволяет клиенту контролировать, как он выполняет итерацию по коллекции. Один вариант использования, который я могу придумать, когда это полезно, - это когда у вас есть неограниченная коллекция, такая как все веб-страницы в Интернете для индексации.

В классической книге GoF контраст между внутренними и внешними итераторами прописан довольно четко.

Фундаментальный вопрос заключается в том, чтобы решить, какая сторона управляет итерацией, итератор или клиент, использующий итератор. Когда клиент управляет итерацией, итератор называется внешним итератором, а когда итератор управляет им, итератор является внутренним итератором. Клиенты, использующие внешний итератор, должны продвигать обход и явно запрашивать следующий элемент у итератора. Напротив, клиент передает внутреннему итератору операцию для выполнения, и итератор применяет эту операцию к каждому элементу....

Внешние итераторы более гибкие, чем внутренние итераторы. Легко сравнить две коллекции на равенство с помощью внешнего итератора, например, но практически невозможно с внутренними итераторами... Но с другой стороны, внутренние итераторы проще в использовании, потому что они определяют логику итерации за вас.

Пример того, как работают внутренние итераторы, см. в Ruby Enumerable API, в котором есть внутренние методы итерации, такие как each. В Ruby идея состоит в том, чтобы передать блок кода (то есть замыкание) внутреннему итератору, чтобы коллекция могла позаботиться о своей итерации.

person Alan    schedule 18.09.2008

важно держать коллекцию отдельно от указателя. итератор указывает на определенное место в коллекции и, таким образом, не является неотъемлемой частью коллекции. таким образом, например, вы можете использовать несколько итераторов для одной и той же коллекции.

недостатком этого разделения является то, что итератор не знает об изменениях, внесенных в коллекцию, по которой он выполняет итерацию. поэтому вы не можете изменить структуру коллекции и ожидать, что итератор продолжит свою работу без «жалоб».

person Amir Arad    schedule 18.09.2008

Использование интерфейса Iterator позволяет любому классу, реализующему его методы, действовать как итераторы. Понятие интерфейса в Java состоит в том, чтобы иметь договорное обязательство предоставлять определенные функции в классе, который implements интерфейс, действовать так, как требуется интерфейсом. Поскольку договорные обязательства должны быть выполнены, чтобы быть действительным классом, другие классы, которые видят класс implements интерфейс и, таким образом, уверены, что класс будет иметь эти определенные функции.

В этом примере вместо того, чтобы реализовать методы (hasNext(), next(), remove()) в самом классе LinkedList, класс LinkedList объявит, что он implements интерфейс Iterator, чтобы другие знали, что LinkedList можно использовать в качестве итератора. В свою очередь, класс LinkedList будет реализовывать методы из интерфейса Iterator (например, hasNext()), поэтому он может функционировать как итератор.

Другими словами, реализация интерфейса — это понятие объектно-ориентированного программирования, позволяющее другим узнать, что определенный класс имеет то, что требуется, чтобы быть тем, чем он себя называет.

Это понятие обеспечивается наличием методов, которые должны быть реализованы классом, реализующим интерфейс. Это гарантирует, что другие классы, которые хотят использовать класс, реализующий интерфейс Iterator, действительно будут иметь методы, которые должны быть у итераторов, такие как hasNext().

Кроме того, следует отметить, что, поскольку Java не имеет множественного наследования, использование интерфейса может использоваться для эмуляции этой функции. Реализуя несколько интерфейсов, можно иметь класс, который является подклассом, чтобы наследовать некоторые функции, а также «наследовать» функции другого, реализуя интерфейс. Например, если бы я хотел иметь подкласс класса LinkedList с именем ReversibleLinkedList, который мог бы выполнять итерацию в обратном порядке, я мог бы создать интерфейс с именем ReverseIterator и заставить его предоставлять метод previous(). Поскольку LinkedList уже реализует Iterator, в новом обратимом списке должны быть реализованы интерфейсы Iterator и ReverseIterator.

Подробнее об интерфейсах можно прочитать на странице Что такое интерфейс? из руководства по Java от Sun.

person coobird    schedule 18.09.2008

Несколько экземпляров интератора могут использоваться одновременно. Подойдите к ним как к локальным курсорам для базовых данных.

Кстати: предпочтение интерфейсов конкретным реализациям теряет связь

Найдите шаблон проектирования итератора и здесь: http://en.wikipedia.org/wiki/Iterator< /а>

person Daniel Hiller    schedule 18.09.2008

Потому что вы можете перебирать что-то, что не является структурой данных. Допустим, у меня есть сетевое приложение, которое получает результаты с сервера. Я могу вернуть эти результаты в оболочку Iterator и пропустить их через любой стандартный код, который принимает объект Iterator.

Думайте об этом как о ключевой части хорошего дизайна MVC. Данные должны каким-то образом попасть из модели (т. е. структуры данных) в представление. Использование Итератора в качестве посредника гарантирует, что реализация Модели никогда не будет раскрыта. Вы можете хранить LinkedList в памяти, извлекать информацию из алгоритма дешифрования или оборачивать вызовы JDBC. Это просто не имеет значения для представления, потому что представление заботится только об интерфейсе Iterator.

person 64BitBob    schedule 18.09.2008

Интересный документ, в котором обсуждаются плюсы и минусы использования итераторов:

http://www.sei.cmu.edu/pacc/CBSE5/Sridhar-cbse5-final.pdf

person user11087    schedule 18.09.2008

Я думаю, что это просто хорошая практика ООП. У вас может быть код, который работает со всеми видами итераторов, и даже дает вам возможность создавать свои собственные структуры данных или просто общие классы, реализующие интерфейс итератора. Вам не нужно беспокоиться о том, какая реализация стоит за этим.

person Alex Argo    schedule 18.09.2008

Просто M2C, если вы не знали: вы можете избежать прямого использования интерфейса итератора в ситуациях, когда for-each будет достаточно.

person chickeninabiscuit    schedule 18.09.2008

В конечном счете, потому что Iterator захватывает абстракцию управления, применимую к большому количеству структур данных. Если вы хорошо разбираетесь в теории категорий, эта статья может поразить вас: Суть шаблона итератора.

person Apocalisp    schedule 18.09.2008

Ну, похоже, что первый пункт списка позволяет многопоточным (или однопоточным, если вы облажались) приложениям не нужно блокировать коллекцию из-за нарушений параллелизма. В .NET, например, вы не можете одновременно перечислять и изменять коллекцию (или список или любой IEnumerable) без блокировки или наследования от IEnumerable и переопределения методов (мы получаем исключения).

person Jason Punyon    schedule 18.09.2008

Итератор просто добавляет общий способ просмотра набора элементов. Одной из приятных функций является функция i.remove(), в которой вы можете удалять элементы из списка, который вы перебираете. Если бы вы просто попытались удалить элементы из списка, как правило, это привело бы к странным эффектам или выбросу и исключению.

Интерфейс подобен контракту для всех вещей, которые его реализуют. Вы в основном говорите... все, что реализует итератор, гарантированно будет иметь эти методы, которые ведут себя одинаково. Вы также можете использовать его для передачи типов итераторов, если это все, что вам нужно в вашем коде. (вам может быть все равно, какой это список.. вы просто хотите передать итератор) Вы можете поместить все эти методы независимо в коллекции, но вы не гарантируете, что они ведут себя одинаково или что они даже имеют одно и то же имя и подписи.

person Arthur Thomas    schedule 18.09.2008

Итераторы — это один из многих шаблонов проектирования, доступных в java. Шаблоны проектирования можно рассматривать как удобные строительные блоки, стили, использование вашего кода/структуры.

Чтобы узнать больше о шаблоне проектирования Iterator, посетите этот веб-сайт, на котором рассказывается об Iterator, а также о многих других шаблонах проектирования. Вот фрагмент с сайта Iterator: http://www.patterndepot.com/put/8/Behavioral.html

Итератор — один из самых простых и наиболее часто используемых шаблонов проектирования. Шаблон Iterator позволяет вам перемещаться по списку или набору данных, используя стандартный интерфейс, не зная деталей внутреннего представления этих данных. Кроме того, вы также можете определить специальные итераторы, которые выполняют некоторую специальную обработку и возвращают только указанные элементы набора данных.

person zxcv    schedule 18.09.2008

Итераторы можно использовать против любой коллекции. Они позволяют определить алгоритм для набора элементов независимо от базовой реализации. Это означает, что вы можете обрабатывать список, набор, строку, файл, массив и т. д.

Через десять лет вы можете изменить свою реализацию List на лучшую реализацию, и алгоритм по-прежнему будет без проблем работать с ней.

person Gili    schedule 18.09.2008

Итератор полезен, когда вы имеете дело с коллекциями в Java.

Используйте For-Each< /b> цикл (Java1.5) для перебора коллекции, массива или списка.

person amadamala    schedule 18.09.2008

Интерфейс java.util.Iterator используется в инфраструктуре коллекций Java, чтобы разрешить модификацию коллекции при выполнении итерации по ней. Если вы просто хотите чисто перебрать всю коллекцию, используйте вместо этого for-each, но преимуществом Iterators является функциональность, которую вы получаете: необязательная операция remove(), и даже лучше для интерфейса List Iterator, который предлагает добавить () и set() тоже. Оба этих интерфейса позволяют перебирать коллекцию и одновременно изменять ее структуру. Попытка изменить коллекцию во время ее итерации с помощью for-each вызовет исключение ConcurrentModificationException, обычно потому, что коллекция неожиданно изменена!

Взгляните на класс ArrayList.

Внутри него есть 2 частных класса (внутренние классы), которые называются Itr и ListItr.

Они реализуют интерфейсы Iterator и ListIterator соответственно.

открытый класс ArrayList..... { //включающий класс

  private class Itr implements Iterator<E> {

        public E next() {
            return ArrayList.this.get(index++); //rough, not exact
        }

        //we have to use ArrayList.this.get() so the compiler will
        //know that we are referring to the methods in the 
        //enclosing ArrayList class

        public void remove() {
            ArrayList.this.remove(prevIndex);
        }

        //checks for...co mod of the list
        final void checkForComodification() {  //ListItr gets this method as well
             if (ArrayList.this.modCount != expectedModCount) { 
                 throw new ConcurrentModificationException();
             }
        }
  }

  private class ListItr extends Itr implements ListIterator<E> {
         //methods inherted....
        public void add(E e) {
            ArrayList.this.add(cursor, e);
        }

        public void set(E e) {
            ArrayList.this.set(cursor, e);
        }
  }

}

Когда вы вызываете методы iterator() и listIterator(), они возвращают новый экземпляр закрытого класса Itr или ListItr, и, поскольку эти внутренние классы находятся «внутри» охватывающего класса ArrayList, они могут свободно изменять ArrayList, не вызывая исключения ConcurrentModificationException. , если только вы не измените список одновременно (одновременно) с помощью методов set() add() или remove() класса ArrayList.

person TheArchon    schedule 21.10.2015