Я только что узнал о том, как 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:
This interface is a member of the Java Collections Framework.
- Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
- Method names have been improved.
Я пробовал погуглить и, похоже, не нашел однозначного ответа. Может ли кто-нибудь пролить свет на то, почему Sun решила их использовать? Это из-за лучшего дизайна? Повышенная безопасность? Хорошая практика ОО?
Любая помощь будет оценена. Спасибо.




Что ж, похоже, что первая точка маркера позволяет многопоточным (или однопоточным, если вы облажались) приложениям не блокировать коллекцию на предмет нарушений параллелизма. В .NET, например, вы не можете перечислять и изменять коллекцию (или список, или любой IEnumerable) одновременно без блокировки или наследования от IEnumerable и методов переопределения (мы получаем исключения).
Интересная статья, в которой обсуждаются плюсы и минусы использования итераторов:
Я думаю, что это просто хорошая ОО-практика. У вас может быть код, который имеет дело со всеми видами итераторов и даже дает вам возможность создавать свои собственные структуры данных или просто общие классы, реализующие интерфейс итератора. Вам не нужно беспокоиться о том, какая реализация стоит за этим.
Итератор просто добавляет общий способ просмотра коллекции элементов. Одной из приятных функций является i.remove (), в которой вы можете удалять элементы из списка, который вы повторяете. Если вы просто попытаетесь удалить элементы из списка, обычно это будет иметь странные эффекты или выброс и исключение.
Интерфейс похож на контракт на все, что его реализует. Вы в основном говорите ... все, что реализует итератор, гарантированно имеет эти методы, которые ведут себя одинаково. Вы также можете использовать его для передачи типов итераторов, если это все, что вам нужно в своем коде. (вам может быть все равно, какой это тип списка ... вы просто хотите передать итератор) Вы можете поместить все эти методы в коллекции независимо, но вы не гарантируете, что они будут вести себя одинаково или что они даже имеют одинаковое имя и подписи.
Потому что вы можете повторять что-то, что не является структурой данных. Допустим, у меня есть сетевое приложение, которое получает результаты с сервера. Я могу вернуть оболочку Iterator вокруг этих результатов и транслировать их с помощью любого стандартного кода, который принимает объект Iterator.
Думайте об этом как о ключевой части хорошего дизайна MVC. Данные должны каким-то образом попасть из модели (т.е. структуры данных) в представление. Использование итератора в качестве посредника гарантирует, что реализация модели никогда не будет раскрыта. Вы можете хранить LinkedList в памяти, извлекать информацию из алгоритма дешифрования или упаковывать вызовы JDBC. Это просто не имеет значения для представления, потому что представление заботится только об интерфейсе Iterator.
Просто M2C, если вы не знали: вы можете избежать прямого использования интерфейса итератора в ситуациях, когда будет достаточно цикла для каждого.
Итераторы - один из многих шаблонов проектирования, доступных в java. Шаблоны проектирования можно рассматривать как удобные строительные блоки, стили, использование вашего кода / структуры.
Чтобы узнать больше о шаблоне проектирования Iterator, посетите этот веб-сайт, на котором рассказывается об Iterator, а также о многих других шаблонах проектирования. Вот отрывок с сайта на Итераторе: http://www.patterndepot.com/put/8/Behavioral.html
The Iterator is one of the simplest and most frequently used of the design patterns. The Iterator pattern allows you to move through a list or collection of data using a standard interface without having to know the details of the internal representations of that data. In addition you can also define special iterators that perform some special processing and return only specified elements of the data collection.
Итераторы можно использовать против любых коллекций. Они позволяют вам определять алгоритм для набора элементов независимо от базовой реализации. Это означает, что вы можете обрабатывать список, набор, строку, файл, массив и т. д.
Через десять лет вы можете изменить свою реализацию List на лучшую реализацию, и алгоритм по-прежнему будет без проблем работать с ней.
Использование интерфейса 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.
Вы можете узнать больше об интерфейсах из Что такое интерфейс? из The Java Tutorial от Sun.
Why is this interface used?
Потому что он поддерживает основные операции, которые позволят клиентскому программисту перебирать любой вид коллекции (примечание: не обязательно Collection в смысле Object).
Why are the methods... not directly coded to the data structure implementation itself?
Они есть, они просто помечены как частные, поэтому вы не можете добраться до них и заняться с ними гадостью. Более конкретно:
Iterator, чтобы он делал то, чего не делают стандартные, без необходимости изменять реальный объект, который он перебирает.Iterators любому количеству клиентов, которое пожелаете, и каждый клиент может перемещаться в свое время и со своей скоростью.Iterators из пакета java.util, в частности, вызовет исключение, если хранилище, которое их поддерживает, будет изменено, пока у вас все еще есть Iterator. Это исключение позволяет узнать, что Iterator теперь может возвращать недопустимые объекты.Для простых программ ничего из этого, вероятно, не имеет смысла. Однако та сложность, которая делает их полезными, быстро откроется вам.
Итератор полезен, когда вы имеете дело с коллекциями в Java.
Используйте цикл Для каждого (Java1.5) для итерации по коллекции, массиву или списку.
В конечном итоге, потому что Iterator захватывает абстракцию элемента управления, которая применима к большому количеству структур данных. Если вы в курсе своей теории категорий, то можете поразить вас этой статьей: Суть паттерна итератора.
Вы спросите: «Почему методы hasNext (), next () и remove () не закодированы напрямую в саму реализацию структуры данных?».
Платформа Java Collections решает определить интерфейс Iterator как внешний по отношению к самой коллекции. Обычно, поскольку каждая коллекция Java реализует интерфейс Iterable, программа Java вызывает iterator для создания своего собственного итератора, чтобы его можно было использовать в цикле. Как отмечали другие, Java 5 позволяет нам напрямую использовать итератор с циклом для каждого.
Вынесение итератора в его коллекцию позволяет клиенту управлять итерацией по коллекции. Один из вариантов использования, который я могу придумать, где это полезно, - это когда у вас есть неограниченная коллекция, такая как все веб-страницы в Интернете для индексации.
В классической книге GoF контраст между внутренними и внешними итераторами прописан довольно четко.
A fundamental issue is deciding which party conrols the iteration, the iterator or the client that uses the iterator. When the client controls the iteration, the iterator is called an external iterator, and when the iterator controls it, the iterator is an internal iterator. Clients that use an external iterator must advance the traversal and request the next element explicitly from the iterator. In contrast, the client hands an internal iterator an operation to perform, and the iterator applies that operation to every element ....
External iterators are more flexible than internal iterators. It's easy to compare two collections for equality with an external iterator, for example, but it's practically impossible with internal iterators ... But on the other hand, internal iterators are easier to use, because they define the iteration logic for you.
Для примера того, как работают внутренние итераторы, см. Ruby Enumerable API, в котором есть внутренние методы итерации, такие как each. В Ruby идея состоит в том, чтобы передать блок кода (то есть замыкание) внутреннему итератору, чтобы коллекция могла позаботиться о своей собственной итерации.
Одновременно можно использовать несколько экземпляров интератора. Подходите к ним как к локальным курсорам для базовых данных.
Кстати: предпочтение интерфейсов по сравнению с конкретными реализациями теряет связь
Ищите шаблон проектирования итератора, и здесь: http://en.wikipedia.org/wiki/Iterator
важно держать коллекцию отдельно от указателя. итератор указывает на определенное место в коллекции и, следовательно, не является ее неотъемлемой частью. таким образом, например, вы можете использовать несколько итераторов для одной и той же коллекции.
Обратной стороной этого разделения является то, что итератор не знает об изменениях, внесенных в коллекцию, которую он выполняет. поэтому вы не можете изменить структуру коллекции и ожидать, что итератор продолжит работу без «жалоб».
Интерфейс java.util.Iterator используется в Java Collections Framework, чтобы разрешить модификацию коллекции, продолжая выполнять ее итерацию. Если вы просто хотите аккуратно перебирать всю коллекцию, используйте вместо этого for-each, но преимуществом Iterators является функциональность, которую вы получаете: необязательная операция remove () и даже лучше для интерфейса List Iterator, который предлагает добавить () и set () тоже. Оба этих интерфейса позволяют выполнять итерацию по коллекции и одновременно изменять ее структурно. Попытка изменить коллекцию во время итерации с помощью for-each вызовет исключение ConcurrentModificationException, обычно из-за неожиданного изменения коллекции!
Взгляните на класс ArrayList
Внутри него есть 2 частных класса (внутренние классы) называется Itr и ListItr
Они реализуют интерфейсы Iterator и ListIterator соответственно.
public class 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.