Idiomatic way to use for-each loop given an iterator?
What I'd probably do is just make a utility class called Deques
which could support this, along with other utilities if desired.
public class Deques {
private Deques() {}
public static <T> Iterable<T> asDescendingIterable(final Deque<T> deque) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return deque.descendingIterator();
}
}
}
}
This is another case where it's really too bad we don't have lambdas and method references yet. In Java 8, you'll be able to write something like this given that the method reference descendingIterator()
matches the signature of Iterable
:
Deque<String> deque = ...
for (String s : (Iterable<String>) deque::descendingIterator) { ... }
Why doesn't the enhanced for loop just accept an iterator?
I want to gather a few of the potential reasons from the various answers as to why the for-each loop doesn't simply accept an iterator.
- Convenience: The for-each loop was created partly for convenience for the common operation of performing an action given each element of a collection. It has no obligation or intention of replacing the explicit use of iterators (obviously if you want to remove elements, you need an explicit reference to the iterator).
- Readability: The for-each loop
for ( Row r : table )
is meant to be extremely readable as "for each row "r" in table...". Seeingfor ( Row r : table.backwardsIterator() )
breaks that readability. - Transparency: If an object is both an
Iterable
and anIterator
, what will be the behaviour? Though it's easy to make a consistent rule (e.g. Iterable before Iterator) the behaviour will be less transparent to developers. Furthermore, this will have to be checked at compile time. - Encapsulation/Scope: This is (in my opinion) the most important reason. The for-each loop is designed to encapsulate the
Iterator
and limits its scope to the loop. This makes the loop "read-only" in two ways: it doesn't expose the iterator, meaning there is nothing (easily) tangible that has its state altered by the loop, nor can you alter the state of the operand in the loop (as you can by interfacing directly with an Iterator viaremove()
). Passing the Iterator yourself necessarily means the Iterator is exposed, making you lose both of those "read-only" attributes of the loop.