Идиоматический способ использования для каждого цикла с учетом итератора?
=========================================================================

Когда расширенный цикл for (цикл foreach) был добавлен в Java, он был настроен для работы с целевым объектом массива или`Iterable`.

Это прекрасно работает для классов Collection, которые реализуют только один тип итерации и, таким образом, имеют один`iterator()` метод.

Но я нахожусь невероятно расстроенным из-за того, что я хочу использовать нестандартный итератор из класса Collection. Например, я недавно пытался помочь кому-то использовать`Deque` как LIFO / стек, но затем печатать элементы в порядке FIFO. Я был вынужден сделать это:

Я теряю преимущества для каждого цикла. Это не просто нажатия клавиш. Мне не нравится выставлять итератор, если мне не нужно, так как легко ошибиться, вызвав`it.next()` дважды и т. д.

Теперь в идеале я думаю, что цикл для каждого должен был принять`Iterator` также. Но это не так. Так есть ли идиоматический способ использования цикла for-each в этих обстоятельствах? Я также хотел бы услышать предложения, которые используют библиотеки общих коллекций, такие как Guava.

Лучшее, что я могу придумать в отсутствие вспомогательного метода / класса:

Который не стоит использовать.

Я бы хотел увидеть что-то подобное в Гуаве`Iterables.wrap` чтобы сделать это идиоматическим, но ничего подобного не нашел. Очевидно, что я мог бы свернуть свою собственную обертку Iterator через метод класса или вспомогательный метод. Есть другие идеи?

**Редактировать:** Как примечание, может ли кто-нибудь дать вескую причину того, почему расширенный цикл for не мог просто принять`Iterator`? Это, вероятно, во многом помогло бы мне жить с нынешним дизайном.

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

Это еще один случай, когда действительно плохо, что у нас еще нет лямбд и ссылок на методы. В Java 8 вы сможете написать что-то вроде этого, учитывая, что ссылка на метод`descendingIterator()` соответствует подписи`Iterable`:



А потом

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

Что касается вашего дополнительного вопроса - я полагаю, потому что цикл for-each действительно должен был сделать вещи короче для сценариев общего назначения. А вызов дополнительного метода делает синтаксис более многословным. Это могло бы поддержать как`Iterable` а также`Iterator`, но что, если переданный объект реализован как? (было бы странно, но все же возможно).



`descendingIterator`было бы лучше написать`descendingIterable()` метод для возврата нисходящего итерируемого на основе deque-, который в основном занимает место вашего анонимного класса. Это кажется довольно разумным для меня. Согласно предложению Колина, итеративная реализация, возвращаемая этим методом, вызовет`descendingIterator` на оригинальном deque каждый раз свой`iterator()` метод был вызван.

Если вытолько получил итератор и хотел бы сохранить его таким, вам нужно написать реализацию`Iterable<T>` который обернул итератор и вернул егоровно один раз, бросив исключение, если`iterator()` называется не раз. Это сработало бы, но было бы довольно уродливо.



Почему расширенный цикл for не принимает итератор?ом, почему цикл for-each не просто принимает итератор.

**удобство**: Цикл for-each был создан частично для удобства обычной операции по выполнению действия с каждым элементом коллекции. У него нет обязательств или намерений заменить явное использование итераторов (очевидно, если вы хотите удалить элементы, вам нужна явная ссылка на итератор).**читабельность**: Цикл для каждого`for ( Row r : table )` предполагается, что он чрезвычайно удобочитаем как "для каждой строки" r "в таблице ...". Проводы`for ( Row r : table.backwardsIterator() )` нарушает эту читаемость.**прозрачность**: Если объект является одновременно`Iterable` **а также** `Iterator`какое будет поведение? Хотя легко создать согласованное правило (например, итерируемое до итератора), поведение будет менее прозрачным для разработчиков. Кроме того, это должно быть проверено во время компиляции.**Инкапсуляция / Scope**Это (на мой взгляд) самая важная причина. Цикл for-each предназначен для инкапсуляции`Iterator` и ограничивает его область до цикла. Это делает цикл «только для чтения» двумя способами: он не отображает итератор, что означает, что нет ничего (легко) осязаемого, если его состояние измененоот цикл, и вы не можете изменить состояние операндав цикл (как вы можете, напрямую взаимодействуя с итератором через`remove()`). Передача Итератора самостоятельно обязательно означает, что Итератор выставлен, и вы потеряете оба этих атрибута цикла «только для чтения».

идиоматический путь в Java 8 (будучи многословным языком) заключается в следующем:

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

Конечно, вы всегда можете просто прибегнуть к[`Iterator.forEachRemaining()`](https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html#forEachRemaining-java.util.function.Consumer-):



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

В качестве следующего шага возвращаемый тип`iter()` может быть свободный интерфейс, так что вы можете сделать:

или, может быть

Вы также должны взглянуть на[op4j](http://www.op4j.org/) который решает многие из этих проблем с очень хорошим API.



 конечно, есть решение для обратного повторяемого сценария, но, к сожалению, вам нужны два шага.[Iterables.reverse ()](https://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html#reverse%28java.util.List%29) занимает`List` в качестве параметра, а не`Iterable`.

Выход:

c  
b  
a



`ImmutableList.copyOf(Iterator)` безопасно преобразовать итератор в итерируемое. Несмотря на кажущуюся простоту зацикливания на итераторе, существуют проблемы, которые скрываются за каждым, и самый безопасный вариант - создать стабильную структуру данных, такую как список.

Это также обсуждается в[Идея Кладбище](https://github.com/google/guava/wiki/IdeaGraveyard#a-method-to-view-an-iterator-as-an-iterable):

Наибольшее беспокойство вызывает то, что`Iterable` Обычно предполагается, что он может создавать несколько независимых итераторов. Док не говорит этого, но`Collection` Док тоже не говорит об этом, и все же мы предполагаем, что это итераторы. У нас были поломки в Google, когда это предположение было нарушено.

Самый простой обходной путь`ImmutableList.copyOf(Iterator)`, который является довольно быстрым, безопасным и обеспечивает много других преимуществ.