Почему итератор Java не является итерируемым?

StackOverflow https://stackoverflow.com/questions/839178

  •  22-07-2019
  •  | 
  •  

Вопрос

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

Тот Самый iterator() метод мог бы просто вернуть this.

Это сделано специально или просто по недосмотру разработчиков Java?

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

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

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

Это было полезно?

Решение

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

Другие советы

Итератор с состоянием. Идея состоит в том, что если вы дважды вызовете Iterable.iterator(), вы получите независимые итераторы - во всяком случае, для большинства итераций. Это явно не будет иметь место в вашем сценарии.

Например, я обычно могу написать:

public void iterateOver(Iterable<String> strings)
{
    for (String x : strings)
    {
         System.out.println(x);
    }
    for (String x : strings)
    {
         System.out.println(x);
    }
}

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

За мои $ 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 для перечислений, которые, как было указано в другом месте, аналогичны итераторам, а не итерабельным.

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

Ваше здоровье,

Как указали другие, Iterator и < a href = "http://docs.oracle.com/javase/7/docs/api/java/lang/Iterable.html"> Iterable - это две разные вещи.

Кроме того, <=> улучшения предшествуют циклам.

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

for (String line : in(lines)) {
  System.out.println(line);
}

Пример реализации:

  /**
   * Adapts an {@link Iterator} to an {@link Iterable} for use in enhanced for
   * loops. If {@link Iterable#iterator()} is invoked more than once, an
   * {@link IllegalStateException} is thrown.
   */
  public static <T> Iterable<T> in(final Iterator<T> iterator) {
    assert iterator != null;
    class SingleUseIterable implements Iterable<T> {
      private boolean used = false;

      @Override
      public Iterator<T> iterator() {
        if (used) {
          throw new IllegalStateException("SingleUseIterable already invoked");
        }
        used = true;
        return iterator;
      }
    }
    return new SingleUseIterable();
  }
<Ч>

В Java 8 адаптация <=> к <=> упрощается:

for (String s : (Iterable<String>) () -> iterator) {

Как уже говорили другие, Iterable может вызываться несколько раз, возвращая свежий Iterator при каждом вызове; Итератор используется только один раз. Таким образом, они связаны, но служат различным целям. Однако, к сожалению, & Quot; compact for & Quot; Метод работает только с итерацией.

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

Хитрость в том, чтобы вернуть анонимную реализацию Iterable, которая фактически запускает работу. Таким образом, вместо того, чтобы выполнять работу, которая генерирует одноразовую последовательность, а затем возвращать Итератор, вы возвращаете Итерируемый, который при каждом обращении к нему повторяет работу. Это может показаться расточительным, но часто вы все равно будете вызывать Iterable один раз, и даже если вы вызываете его несколько раз, он все еще имеет разумную семантику (в отличие от простой оболочки, которая делает Iterator & Quot; похожим на " a Iterable, это не даст сбоя, если его использовать дважды).

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

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...
    }
}

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

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

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

Невероятно, но еще никто не дал этот ответ. Вот как вы можете & Легко & Quot; переберите Iterator с помощью новой Java 8 Iterator.forEachRemaining() метод:

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

Конечно, есть " проще " решение, которое работает с циклом foreach напрямую, заключая Iterable в <=> лямбду:

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

Iterator это интерфейс, который позволяет вам перебирать что-то. Это реализация перемещения какой-то коллекции.

Iterable - это функциональный интерфейс, который обозначает, что что-то содержит доступный итератор.

В Java8 это делает жизнь довольно легкой ... Если у вас есть <=>, но вам нужен <=>, вы можете просто это сделать:

Iterator<T> someIterator;
Iterable<T> = ()->someIterator;

Это также работает в цикле for:

for (T item : ()->someIterator){
    //doSomething with item
}

Я также вижу, что многие так делают:

public Iterator iterator() {
    return this;
}

Но это не делает это правильно! Этот метод не будет тем, что вы хотите!

Метод iterator() должен возвращать новый итератор, начиная с нуля. Так что нужно сделать что-то вроде этого:

public class IterableIterator implements Iterator, Iterable {

  //Constructor
  IterableIterator(IterableIterator iter)
  {
    this.initdata = iter.initdata;
  }
  // methods of Iterable

  public Iterator iterator() {
    return new MyClass(this.somedata);
  }

  // methods of Iterator

  public boolean hasNext() {
    // ...
  }

  public Object next() {
    // ...
  }

  public void remove() {
    // ...
  }
}

Вопрос: есть ли способ заставить абстрактный класс выполнять это? Чтобы получить IterableIterator, нужно всего лишь реализовать два метода next () и hasNext ()

Если вы пришли сюда в поисках обходного пути, вы можете использовать Итератор, поддающийся повторению.(доступно для 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

Я согласен с принятым ответом, но хочу добавить свое собственное объяснение.

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

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

Было бы неплохо, если бы Java for loop принимала как Iterator, так и Iterable.

Для простоты Iterator и Iterable - это две разные концепции, Iterable - это просто сокращение для " я могу вернуть Iterator " ;. Я думаю, что ваш код должен быть:

for(Object o : someContainer) {
}

с экземпляром 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

Итераторы с состоянием, у них есть " next " элемент и стать " исчерпаны " однажды перебрал Чтобы увидеть, в чем проблема, запустите следующий код, сколько цифр напечатано?

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());
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top