java реализация - Почему Итератор Java не является Iterable?




8 Answers

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

паттерн iterator

Почему интерфейс Iterator не расширяет Iterable ?

Метод iterator() может просто вернуть this .

Это специально или просто надзор над дизайнерами Java?

Было бы удобно использовать цикл for-each с итераторами следующим образом:

for(Object o : someContainer.listSomeObjects()) {
    ....
}

где listSomeObjects() возвращает итератор.




Для моих $ 0,02 я полностью согласен с тем, что Iterator не должен реализовывать Iterable, но я думаю, что расширенный цикл for должен принять либо. Я думаю, что весь аргумент «сделать итераторы итерируемый» возникает как работа с дефектом на языке.

Вся причина введения расширенного цикла for заключалась в том, что он «устраняет тяжелую работу и погрешность итераторов и переменных индекса при повторении массивов и массивов» [ 1 ].

Collection<Item> items...

for (Iterator<Item> iter = items.iterator(); iter.hasNext(); ) {
    Item item = iter.next();
    ...
}

for (Item item : items) {
    ...
}

Почему же этот же аргумент не выполняется для итераторов?

Iterator<Iter> iter...
..
while (iter.hasNext()) {
    Item item = iter.next();
    ...
}

for (Item item : iter) {
    ...
}

В обоих случаях вызовы hasNext () и next () были удалены, и нет ссылки на итератор во внутреннем цикле. Да, я понимаю, что Iterables можно повторно использовать для создания нескольких итераторов, но все это происходит за пределами цикла for: внутри цикла есть только передовая прогрессия по одному элементу за элементы, возвращаемые итератором.

Кроме того, позволяя это также облегчить использование цикла for для перечислений, которые, как было указано в другом месте, аналогичны Iterators not Iterables.

Поэтому не делайте Iterator реализующим Iterable, но обновляйте цикл for, чтобы принять это.

Ура,




Как говорили другие, Iterable можно вызвать несколько раз, возвращая новый Iterator для каждого вызова; Итератор используется только один раз. Поэтому они связаны, но служат различным целям. Однако, к сожалению, метод «компактный» работает только с итерируемым.

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

Хитрость заключается в возврате анонимной реализации Iterable, которая фактически запускает работу. Поэтому вместо выполнения работы, которая генерирует одноразовую последовательность, а затем возвращает Итератор над этим, вы возвращаете Iterable, который при каждом обращении выполняет повторную работу. Это может показаться расточительным, но часто вы будете называть Iterable один раз в любом случае, и даже если вы его вызываете несколько раз, у него все еще есть разумная семантика (в отличие от простой обертки, которая делает Итератор «похожим на« Iterable », t сбой при использовании дважды).

Например, скажем, у меня есть DAO, который предоставляет серию объектов из базы данных, и я хочу предоставить доступ к нему через итератор (например, чтобы не создавать все объекты в памяти, если они не нужны). Теперь я могу просто вернуть итератор, но это делает использование возвращаемого значения в цикле уродливым. Поэтому вместо этого я обертываю все в anon Iterable:

class MetricDao {
    ...
    /**
     * @return All known metrics.
     */
    public final Iterable<Metric> loadAll() {
        return new Iterable<Metric>() {
            @Override
            public Iterator<Metric> iterator() {
                return sessionFactory.getCurrentSession()
                        .createQuery("from Metric as metric")
                        .iterate();
            }
        };
    }
}

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

class DaoUser {
    private MetricDao dao;
    for (Metric existing : dao.loadAll()) {
        // do stuff here...
    }
}

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

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

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




Невероятно, никто еще не ответил на этот ответ. Вот как вы можете «легко» выполнить итерацию по Iterator с помощью нового метода Java 8 Iterator.forEachRemaining() :

Iterator<String> it = ...
it.forEachRemaining(System.out::println);

Конечно, есть «более простое» решение, которое напрямую работает с циклом foreach, обертывая Iterator в Iterable лямбда:

for (String s : (Iterable<String>) () -> it)
    System.out.println(s);



Если вы пришли сюда в поисках обходного пути, вы можете использовать IteratorIterable . (доступно для Java 1.6 и выше)

Пример использования (изменение вектора).

import java.util.Vector;
import org.apache.commons.collections4.iterators.IteratorIterable;
import org.apache.commons.collections4.iterators.ReverseListIterator;
public class Test {
    public static void main(String ... args) {
        Vector<String> vs = new Vector<String>();
        vs.add("one");
        vs.add("two");
        for ( String s: vs ) {
            System.out.println(s);
        }
        Iterable<String> is
            = new IteratorIterable(new ReverseListIterator(vs));
        for ( String s: is ) {
            System.out.println(s);
        }
    }
}

печать

one
two
two
one






Итераторы с точки зрения состояния, они имеют «следующий» элемент и становятся «измученными» после повторения. Чтобы узнать, в чем проблема, выполните следующий код, сколько номеров напечатано?

Iterator<Integer> iterator = Arrays.asList(1,2,3).iterator();
Iterable<Integer> myIterable = ()->iterator;
for(Integer i : myIterable) System.out.print(i);
System.out.println();
for(Integer i : myIterable) System.out.print(i);



Вы можете попробовать следующий пример:

List ispresent=new ArrayList();
Iterator iterator=ispresent.iterator();
while(iterator.hasNext())
{
    System.out.println(iterator.next());
}



Related

java iterator iterable