Java: почему не может выполнить итерации по итератору?

Я читал, Почему Итератор Java не является Повторяемым? и Почему Перечисления не Повторяемы?, но я все еще не понимаю почему это:

void foo(Iterator it) {
  for (X x : it) {
    bar(x);
    baz(x);
  }
}

не был сделан возможным. Другими словами, если я не пропускаю что-то, вышеупомянутое, возможно, было хорошим и допустимым синтаксическим сахаром для:

void foo(Iterator it) {
  for (X x; it.hasNext();) {
    x = it.next();
    bar(x);
    baz(x);
  }
}

20
задан Community 23 May 2017 в 12:34
поделиться

5 ответов

, но я до сих пор не понимаю, почему это [...] не стало возможным.

Я вижу несколько причин:

  1. Итераторы не могут использоваться повторно, поэтому for / each будет использовать итератор - возможно, это не некорректное поведение, но неинтуитивно для тех, кто не знает, как for / каждый обессахарен.
  2. Итераторы не так часто появляются в коде «голыми», поэтому они усложнили бы JLS с небольшим выигрышем (конструкция for / each и так достаточно плохая, работает с обоими Итерируемый s и массивы).
  3. Есть простой способ обхода . Выделение нового объекта только для этого может показаться немного расточительным, но выделение и так дешево, и в большинстве случаев анализ избегания избавит вас даже от этих небольших затрат. (Почему они не включили этот обходной путь в служебный класс Iterables , аналогичный Collections и Arrays , я не понимаю).)
  4. ( Вероятно, неправда - см. Комментарии.) Мне кажется, я припоминаю, что JLS может ссылаться только на вещи в java.lang [необходима цитата] , поэтому им придется создать интерфейс Iterator в java.lang , который java.util.Iterator расширяется без добавления чего-либо. Теперь у нас есть два функционально эквивалентных интерфейса итератора. 50% нового кода, использующего голые итераторы, выберут версию java.lang , остальные будут использовать версию java.util . Наступает хаос, возникает множество проблем с совместимостью и т. Д.

Я думаю, что пункты 1-3 очень соответствуют тому, как выглядит философия дизайна языка Java: не удивляйте новичков, не усложняйте спецификацию, если она не дает явного преимущества, которое затмевает затраты. , и не делайте с языковой функцией того, что можно сделать с библиотекой.

Те же аргументы объясняют, почему java.util.Enumeration тоже не Iterable .

9
ответ дан 29 November 2019 в 23:52
поделиться

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

private static <T> Iterable<T> iterable(final Iterator<T> it){
     return new Iterable<T>(){ public Iterator<T> iterator(){ return it; } };
}

//....
{
     // ...
     // Now we can use:
     for ( X x : iterable(it) ){
        // do something with x
     }
     // ...
}
//....

Тем не менее, лучше всего просто передать интерфейс Iterable вместо Iterator

19
ответ дан 29 November 2019 в 23:52
поделиться

Итераторы не предназначены для повторного использования (т. Е. Используются более чем в одном цикле итераций). В частности, Iterator.hasNext () гарантирует, что вы можете безопасно вызвать Iterator.next () и действительно получить следующее значение из базовой коллекции.

Когда один и тот же итератор используется в двух одновременно выполняющихся итерациях (допустим, в многопоточном сценарии), это обещание больше не может выполняться:

while(iter.hasNext() {
   // Now a context switch happens, another thread is performing
   //    iter.hasNext(); x = iter.next();

  String s = iter.next();  
          // A runtime exception is thrown because the iterator was 
          // exhausted by the other thread
}

Такие сценарии полностью нарушают протокол, предлагаемый Iterator. Фактически, они могут возникать даже в однопоточной программе: цикл итерации вызывает другой метод, который использует тот же итератор для выполнения своей собственной итерации. Когда этот метод возвращается, вызывающий вызывает вызов Iterator.next () , который, опять же, терпит неудачу.

2
ответ дан 29 November 2019 в 23:52
поделиться

Потому что for-each разработан для чтения примерно так:

for each element of [some collection of elements]

Итератор не является [некоторый набор элементов] . Массив и Iterable есть.

0
ответ дан 29 November 2019 в 23:52
поделиться

Синтаксис for(Type t : iterable) действителен только для классов, реализующих Iterable.

Итератор не реализует iterable.

Вы можете выполнять итерацию над такими вещами, как Collection, List или Set, потому что они реализуют Iterable.

Следующий код эквивалентен:

for (Type t: list) {
    // do something with t
}

и

Iterator<Type> iter = list.iterator();
while (iter.hasNext()) {
    t = iter.next();
    // do something with t
}

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

6
ответ дан 29 November 2019 в 23:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: