Iterable represents a collection which could be traversed, it can return as many iterators as you want, each representing its own state of traversing, one iterator may be pointing to the first element, while another may be pointing to the 3rd element.
An iterator is an object that implements the __iter__ method which returns itself and the __next__ method which returns the next element. Iterators are also iterables. However, they're iterables that become exhausted while iterables will never exhausted.
Both Iterator and Iterable are interfaces in Java that look very similar and are often confusing for beginners, but both are two different things. In short, if any class implements the Iterable interface, it gains the ability to iterate over an object of that class using an Iterator.
Iterator is an interface, which has implementation for iterate over elements. Iterable is an interface which provides Iterator.
An iterator is stateful. The idea is that if you call Iterable.iterator()
twice you'll get independent iterators - for most iterables, anyway. That clearly wouldn't be the case in your scenario.
For example, I can usually write:
public void iterateOver(Iterable<String> strings)
{
for (String x : strings)
{
System.out.println(x);
}
for (String x : strings)
{
System.out.println(x);
}
}
That should print the collection twice - but with your scheme the second loop would always terminate instantly.
Because an iterator generally points to a single instance in a collection. Iterable implies that one may obtain an iterator from an object to traverse over its elements - and there's no need to iterate over a single instance, which is what an iterator represents.
For my $0.02, I completely agree that Iterator should not implement Iterable, but I think the enhanced for loop should accept either. I think the whole "make iterators iterable" argument comes up as a work around to a defect in the language.
The whole reason for the introduction of the enhanced for loop was that it "eliminates the drudgery and error-proneness of iterators and index variables when iterating over collections and arrays" [1].
Collection<Item> items...
for (Iterator<Item> iter = items.iterator(); iter.hasNext(); ) {
Item item = iter.next();
...
}
for (Item item : items) {
...
}
Why then does this same argument not hold for iterators?
Iterator<Iter> iter...
..
while (iter.hasNext()) {
Item item = iter.next();
...
}
for (Item item : iter) {
...
}
In both cases, the calls to hasNext() and next() have been removed, and there is no reference to the iterator in the inner loop. Yes, I understand that Iterables can be re-used to create multiple iterators, but that all happens outside of the for loop: inside the loop there is only ever a forward progression one item at a time over the items returned by the iterator.
Also, allowing this would also make it easy to use the for loop for Enumerations, which, as has been pointed out elsewhere, are analogous to Iterators not Iterables.
So don't make Iterator implement Iterable, but update the for loop to accept either.
Cheers,
As pointed out by others, Iterator
and Iterable
are two different things.
Also, Iterator
implementations predate enhanced for loops.
It is also trivial to overcome this limitation with a simple adapter method that looks like this when used with static method imports:
for (String line : in(lines)) {
System.out.println(line);
}
Sample implementation:
/**
* 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();
}
In Java 8 adapting an Iterator
to an Iterable
gets simpler:
for (String s : (Iterable<String>) () -> iterator) {
Incredibly, no one else has given this answer yet. Here's how you can "easily" iterate over an Iterator
by using the new Java 8 Iterator.forEachRemaining()
method:
Iterator<String> it = ...
it.forEachRemaining(System.out::println);
Of course, there's a "simpler" solution that works with the foreach loop directly, wrapping the Iterator
in an Iterable
lambda:
for (String s : (Iterable<String>) () -> it)
System.out.println(s);
As others have said, an Iterable can be called multiple times, returning a fresh Iterator on each call; an Iterator is used just once. So they are related, but serve different purposes. Frustratingly, however, the "compact for" method works only with an iterable.
What I will describe below is one way to have the best of both worlds - returning an Iterable (for nicer syntax) even when the underlying sequence of data is one-off.
The trick is to return an anonymous implementation of the Iterable that actually triggers the work. So instead of doing the work that generates a one-off sequence and then returning an Iterator over that, you return an Iterable which, each time it is accessed, redoes the work. That might seem wasteful, but often you will only call the Iterable once anyway, and even if you do call it multiple times, it still has reasonable semantics (unlike a simple wrapper that makes an Iterator "look like" an Iterable, this won't fail if used twice).
For example, say I have a DAO that provides a series of objects from a database, and I want to provide access to that via an iterator (eg. to avoid creating all objects in memory if they are not needed). Now I could just return an iterator, but that makes using the returned value in a loop ugly. So instead I wrap everything in an anon Iterable:
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();
}
};
}
}
this can then be used in code like this:
class DaoUser {
private MetricDao dao;
for (Metric existing : dao.loadAll()) {
// do stuff here...
}
}
which lets me use the compact for loop while still keeping incremental memory use.
This approach is "lazy" - the work is not done when the Iterable is requested, but only later when the contents are iterated over - and you need to be aware of the consequences of that. In the example with a DAO that means iterating over the results within the database transaction.
So there are various caveats, but this can still be a useful idiom in many cases.
Iterator
is an interface which allows you to iterate over something. It is an implementation of moving through a collection of some kind.
Iterable
is a functional interface which denotes that something contains an accessible iterator.
In Java8, this makes life pretty easy... If you have an Iterator
but need an Iterable
you can simply do:
Iterator<T> someIterator;
Iterable<T> = ()->someIterator;
This also works in the for-loop:
for (T item : ()->someIterator){
//doSomething with item
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With