Я думаю, что это полностью законно - Итератор
- это просто поток "материала". Почему поток обязательно должен быть ограничен?
Многие другие языки (например, Scala) имеют встроенную концепцию неограниченных потоков, и их можно повторять. Например, использование scalaz
scala> val fibs = (0, 1).iterate[Stream](t2 => t2._2 -> (t2._1 + t2._2)).map(_._1).iterator
fibs: Iterator[Int] = non-empty iterator
scala> fibs.take(10).mkString(", ") //first 10 fibonnacci numbers
res0: String = 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
EDIT: С точки зрения принципа наименьшего удивления, я думаю, это полностью зависит от контекста. Например, что я могу ожидать от этого метода?
public Iterator<Integer> fibonacciSequence();
Вся суть Итератора
в том, что он ленив, то есть дает вам столько объектов, сколько вы просите. Если пользователь запрашивает все объекты бесконечного Итератора
, это его проблема, а не ваша.
Да. Вам просто нужны разные критерии, когда следует прекратить итерацию.
Концепция бесконечных списков очень распространена в языках ленивых вычислений, таких как Haskell, и приводит к совершенно иному дизайну программ.
Я могу представить любое количество применений бесконечного итератора. Например, как насчет программы, перебирающей сообщения о состоянии, отправляемые другим сервером или фоновым процессом. Хотя в реальной жизни сервер, по-видимому, рано или поздно остановится, с точки зрения программы он может просто продолжать чтение, пока не будет остановлен чем-то, не имеющим отношения к итератору, достигающему его конца.
Это, безусловно, было бы необычно и, как говорили другие, должно быть тщательно задокументировано. Но я бы не признал это неприемлемым.
Подумайте, есть ли у вас функция-генератор. Итератор может быть разумным интерфейсом для генератора, а может и не быть, как вы заметили.
С другой стороны, в Python есть генераторы, которые do завершаются.
Бесконечный итератор очень полезен при создании бесконечных данных, например, линейных повторяющихся последовательностей, таких как последовательность Фибоначчи.
Поэтому совершенно нормально использовать такие итераторы.
Хотя я тоже считаю, что это законно, я хотел бы добавить, что такой Iterator
(точнее: Iterable
, создающий такой Iterator
), не будет хорошо работать с расширенным циклом for (он же for-each-loop):
for (Object o : myIterable) {
...
}
Поскольку код внутри расширенного цикла for не имеет прямого доступа в итератор, он не может вызвать remove ()
на итераторе.
Таким образом, чтобы завершить цикл, необходимо выполнить одно из следующих действий:
List
итератора
и удалить объекты напрямую, что может вызвать ConcurrentModificationException
break
для выхода из цикла Exception
для выхода из цикла return
для выхода the loop Все альтернативы, кроме последней, не совсем лучший способ оставить расширенный цикл for.
"Обычный" цикл for (или любой другой цикл вместе с явной переменной Iterator
), конечно, будет работать нормально:
for (Iterator it = getIterator(); it.hasNext();) {
Object o = it.next()
...
}
Это может быть семантика, но итератор должен старательно возвращать следующий элемент, независимо от того, когда он закончится. Завершение - это побочный эффект для коллекции, хотя он может показаться обычным побочным эффектом.
Тем не менее, в чем разница между бесконечностью и коллекцией из 10 триллионов предметов? Звонящий либо хочет их всех, либо не хочет. Позвольте вызывающему абоненту решить, сколько элементов вернуть или когда закончить.
Я бы не сказал, что вызывающий не может использовать конструкцию for-each. Он мог бы, пока ему нужны были все предметы.
Что-то в документации к коллекции, например «может быть бесконечная коллекция», было бы подходящим, но не «бесконечный итератор».
Это совершенно законное использование - при условии, что это должным образом задокументировано .
Использование имени CyclicIterator
является хорошей идеей, поскольку оно предполагает, что цикл на итераторе вполне может быть бесконечным, если случай выхода из цикла не определен должным образом.
Фактически, Итератор
происходит от Iterable
, не a Collection
, независимо от JavaDoc API говорит. Последний расширяет первый, и поэтому он может также генерировать Iterator
, но вполне разумно, чтобы Iterable
не был Collection
. Фактически, есть даже несколько классов Java, которые реализуют Iterable
, но не Collection
.
Теперь, что касается ожиданий ... конечно, бесконечный итератор не должен быть доступен без четкого указания на то, что это так. Но иногда ожидания могут быть обманчивыми. Например, можно было бы ожидать, что InputStream
всегда будет заканчиваться, но на самом деле это не является его требованием. Точно так же Iterator
, возвращающий строки, прочитанные из такого потока, может никогда не закончиться.