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

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

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

открытый интерфейс Iterator

Итератор над коллекцией. Итератор занимает место перечисления в структуре коллекций Java. Итераторы отличаются от перечислений двумя способами:

  • Итераторы позволяют вызывающей стороне удалять элементы из базовой коллекции во время итерации с четко определенной семантикой.
  • Имена методов были улучшены.
Этот интерфейс является членом Java Collections Framework.

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

Любая помощь будет оценена. Благодарю.

16 ответов

Решение

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

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

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

Они просто помечены как Приватные, так что вы не можете проникнуть в них и испортить их. Более конкретно:

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

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

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

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

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

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

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

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

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

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

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

С использованием 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.

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

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

Ищите шаблон дизайна итератора, и здесь: http://en.wikipedia.org/wiki/Iterator

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

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

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

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

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

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

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

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

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

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

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

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

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

Интерфейс java.util.Iterator используется в платформе Java Collections Framework, чтобы разрешить изменение коллекции, продолжая итерацию по ней. Если вы просто хотите аккуратно выполнить итерацию по всей коллекции, вместо этого используйте for-each, но плюс Итераторов - это функциональность, которую вы получаете: необязательная операция 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.

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

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

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

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

Другие вопросы по тегам