Почему Iterator
интерфейс не расширяется Iterable
?
iterator()
Метод может просто вернуться this
.
Это специально или просто недосмотр разработчиков Java?
Было бы удобно иметь возможность использовать цикл for-each с итераторами:
for(Object o : someContainer.listSomeObjects()) {
....
}
где listSomeObjects()
возвращает итератор.
Ответы:
Потому что итератор обычно указывает на один экземпляр в коллекции. Итерируемость подразумевает, что можно получить итератор от объекта для обхода его элементов - и нет необходимости перебирать один экземпляр, который представляет собой итератор.
источник
Итератор с состоянием. Идея состоит в том, что если вы
Iterable.iterator()
дважды позвоните, вы получите независимые итераторы - в любом случае, для большинства итераций. Это явно не будет иметь место в вашем сценарии.Например, я обычно могу написать:
Это должно напечатать коллекцию дважды - но с вашей схемой второй цикл всегда завершится мгновенно.
источник
iterator
и используете результат, он должен выполнить итерацию по коллекции, чего не произойдет, если этот же объект уже прошел итерацию по коллекции. Можете ли вы дать какую-либо правильную реализацию (кроме пустой коллекции), где один и тот же итератор возвращается дважды?iterable
дважды даст вам независимые итераторы.За мои $ 0,02 я полностью согласен с тем, что Iterator не должен реализовывать Iterable, но я думаю, что расширенный цикл for также должен принять. Я думаю, что весь аргумент «сделай итераторы итеративными» подходит для обхода дефекта в языке.
Основная причина введения расширенного цикла for заключалась в том, что он «устраняет трудоемкость и подверженность ошибкам итераторов и индексных переменных при переборе коллекций и массивов» [ 1 ].
Почему же этот аргумент не подходит для итераторов?
В обоих случаях вызовы hasNext () и next () были удалены, и во внутреннем цикле нет ссылки на итератор. Да, я понимаю, что Iterables можно повторно использовать для создания нескольких итераторов, но все это происходит вне цикла for: внутри цикла всегда имеется только прямая прогрессия по одному элементу за раз по сравнению с элементами, возвращаемыми итератором.
Кроме того, разрешение этого также облегчит использование цикла for для перечислений, которые, как было указано в других местах, аналогичны итераторам, а не итерации.
Так что не заставляйте Iterator реализовывать Iterable, но обновите цикл for, чтобы принять либо.
Ура,
источник
for(item : iter) {...}
синтаксисом, то он вызовет ошибку, когда один и тот же итератор будет повторен дважды. Представьте, чтоIterator
передается вiterateOver
метод, а неIterable
в этом примере .for (String x : strings) {...}
илиwhile (strings.hasNext()) {...}
: если вы попытаетесь дважды повторить итератор во второй раз, вы не получите результатов, поэтому я не рассматриваю это как аргумент против использования расширенного синтаксиса. Ответ Джона другой, потому что он показывает, как завершениеIterator
вIterable
может вызвать проблемы, так как в этом случае вы могли бы использовать его столько раз, сколько захотите.Как указывают другие,
Iterator
иIterable
это две разные вещи.Кроме того,
Iterator
реализации предшествуют усовершенствованным циклам.Это также тривиально, чтобы обойти это ограничение с помощью простого метода адаптера, который выглядит следующим образом при использовании статического метода импорта:
Пример реализации:
В Java 8 адаптация
Iterator
к aIterable
становится проще:источник
for (String s : (Iterable<String>) () -> iterator)
Как уже говорили другие, Iterable может вызываться несколько раз, возвращая новый Iterator при каждом вызове; Итератор используется только один раз. Таким образом, они связаны, но служат различным целям. Однако, к сожалению, метод «компактный для» работает только с итерацией.
Ниже я опишу один из способов получить лучшее из обоих миров - вернуть Iterable (для лучшего синтаксиса), даже если базовая последовательность данных одноразовая.
Хитрость заключается в том, чтобы вернуть анонимную реализацию Iterable, которая фактически запускает работу. Таким образом, вместо того, чтобы выполнять работу, которая генерирует одноразовую последовательность, а затем возвращать Итератор, вы возвращаете Итерируемый, который при каждом обращении к нему повторяет работу. Это может показаться расточительным, но часто вы все равно будете вызывать Iterable только один раз, и даже если вы вызываете его несколько раз, он все еще имеет разумную семантику (в отличие от простой оболочки, которая делает Iterator «похожим» на Iterable, это выиграет » не удается, если используется дважды).
Например, скажем, у меня есть DAO, который предоставляет серию объектов из базы данных, и я хочу предоставить доступ к нему через итератор (например, чтобы избежать создания всех объектов в памяти, если они не нужны). Теперь я могу просто вернуть итератор, но это делает использование возвращаемого значения в цикле уродливым. Поэтому вместо этого я обертываю все в один итеративный:
это может тогда использоваться в коде как это:
который позволяет мне использовать компактный цикл for, сохраняя при этом добавочное использование памяти.
Этот подход является «ленивым» - работа не выполняется, когда запрашивается Iterable, а только позже, когда содержимое повторяется, - и вам нужно знать о последствиях этого. В примере с DAO это означает итерацию результатов в транзакции базы данных.
Таким образом, существуют различные предостережения, но во многих случаях это может быть полезной идиомой.
источник
returning a fresh Iterator on each call
должны сопровождаться, почему, например, чтобы предотвратить проблему параллелизма ...Невероятно, но еще никто не дал этот ответ. Вот как вы можете «легко» выполнять итерации
Iterator
с помощью новогоIterator.forEachRemaining()
метода Java 8 :Конечно, есть «более простое» решение, которое работает с циклом foreach напрямую, заключая
Iterator
вIterable
лямбду:источник
Iterator
это интерфейс, который позволяет вам перебирать что-то Это реализация перемещения какой-то коллекции.Iterable
это функциональный интерфейс, который обозначает, что что-то содержит доступный итератор.В Java8 это делает жизнь довольно легкой ... Если у вас есть,
Iterator
но нужна,Iterable
вы можете просто сделать:Это также работает в цикле for:
источник
Я согласен с принятым ответом, но хочу добавить собственное объяснение.
Итератор представляет состояние обхода, например, вы можете получить текущий элемент из итератора и перейти к следующему.
Iterable представляет коллекцию, которую можно обойти, он может вернуть столько итераторов, сколько вы хотите, каждый из которых представляет свое собственное состояние обхода, один итератор может указывать на первый элемент, а другой может указывать на 3-й элемент.
Было бы хорошо, если бы цикл Java for принимал и Iterator, и Iterable.
источник
Чтобы избежать зависимости от
java.util
пакетаСогласно исходному JSR, расширенному циклу for для языка программирования Java ™ , предложенные интерфейсы:
java.lang.Iterable
java.lang.ReadOnlyIterator
(предлагается установить на него
java.util.Iterator
, но, видимо, этого не произошло)… Были разработаны для использования
java.lang
пространства имен пакета, а неjava.util
.Процитирую JSR:
Кстати, старый
java.util.Iterable
получил новыйforEach
метод в Java 8+ для использования с лямбда-синтаксисом (передача aConsumer
).Вот пример.
List
Интерфейс расширяетIterable
интерфейс, как и любой список несетforEach
метод.источник
Я также вижу, что многие делают это:
Но это не делает это правильно! Этот метод не будет тем, что вы хотите!
Предполагается, что метод
iterator()
возвращает новый итератор, начиная с нуля. Так что нужно сделать что-то вроде этого:Вопрос в том, будет ли какой-нибудь способ сделать абстрактный класс, выполняющий это? Чтобы получить IterableIterator, нужно всего лишь реализовать два метода next () и hasNext ()
источник
Если вы пришли сюда в поисках обходного пути, вы можете использовать IteratorIterable . (доступно для Java 1.6 и выше)
Пример использования (реверсирование вектора).
печать
источник
Для простоты Iterator и Iterable - это две разные концепции, Iterable - это просто сокращение от «Я могу вернуть Iterator». Я думаю, что ваш код должен быть:
с экземпляром someContainer
SomeContainer extends Iterable<Object>
источник
Кроме того: в Scala есть метод toIterable () в Iterator. Смотрите неявное или явное преобразование scala из итератора в итеративное
источник
В соответствующей заметке вы можете найти адаптер IteratorIterable в Apache Commons Collections4 полезным. Просто создайте экземпляр из итератора, и вы получите соответствующий итератор.
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html
ID: org.apache.commons: commons-collection4: 4.0
источник
Итераторы с состоянием, имеют «следующий» элемент и становятся «исчерпанными» после итерации. Чтобы увидеть, в чем проблема, запустите следующий код, сколько чисел напечатано?
источник
Вы можете попробовать следующий пример:
источник