191

Why does the Iterator interface not extend Iterable?

The iterator() method could simply return this.

Is it on purpose or just an oversight of Java's designers?

It would be convenient to be able to use a for-each loop with iterators like this:

for(Object o : someContainer.listSomeObjects()) {
    ....
}

where listSomeObjects() returns an iterator.

Dan Hulme
  • 14,779
  • 3
  • 46
  • 95
Łukasz Bownik
  • 6,149
  • 12
  • 42
  • 60
  • 1
    OK - I see your point buut . it would still be convenient even if it broke a semantics a little :] Thank U for all the answers :] – Łukasz Bownik May 08 '09 at 10:53
  • I realize this question was asked long ago, but - do you mean any Iterator, or just an Iterator relating to some Collection? – einpoklum Jan 25 '15 at 21:33
  • Just FYI, several years after this question, JavaScript got the concepts of "iterable" and "iterator" (though being JavaScript, a bit different from Java's). All of the iterators you get from the standard JavaScript library ... are also iterable, because they implement the relevant method with `return this`. :-) – T.J. Crowder Apr 14 '21 at 07:31

16 Answers16

226

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • It's entirely implementation dependent whether you'll get independent iterators. You have no way of ensuring they are. – Chris K Dec 19 '09 at 20:37
  • 18
    @Chris: If an implementation returns the same iterator twice, how on earth could it fulfil the contract of Iterator? If you call `iterator` and use the result, it has to iterate over the collection - which it won't do if that same object has already iterated over the collection. Can you give *any* correct implementation (other than for an empty collection) where the same iterator is returned twice? – Jon Skeet Dec 19 '09 at 20:57
  • 7
    This is a great response Jon, you've really got the crux of the problem here. Shame this isn't the accepted answer! The contract for Iterable is strictly defined, but the above is a great explanation of the reasons why allowing Iterator to implement Iterable (for foreach) would break the spirit of the interface. – joelittlejohn Nov 12 '10 at 16:27
  • 4
    @JonSkeet while an Iterator is stateful, the contract of Iterable says nothing about being able to be used twice to get independent iterators, even tho it is the scenario in 99% cases. All Iterable says is that it allows an object to be the target of foreach. For those of you who are unhappy with Iterator not being an Iterable, you are free to make such an Iterator. It wouldn't break the contract one bit. However - Iterator itself should not be Iterable since that would make it circularly dependent and that lays the ground for icky design. – Centril Jan 25 '14 at 04:49
  • 2
    @Centril: Right. Have edited to indicate that *usually* calling `iterable` twice will give you independent iterators. – Jon Skeet Jan 25 '14 at 07:59
  • 2
    This does get to the heart of it. It would almost be possible to implement an Iterable Iterator that implements .iterator() by resetting itself, but this design would still break in some circumstances, for example, if it was passed to a method that takes an Iterable and loops over all possible pairs of elements by nesting for-each loops. – Theodore Murdock Aug 05 '14 at 16:58
  • While I am quite late to the game here, this should be Community Wiki and the Accepted Answer. It correctly identifies WHY a Iterator can never be Iterable. And it's all down to the State it carries. – Andrew T Finnell Aug 29 '18 at 16:29
  • 1
    @AndrewTFinnell Out of interest, why do you think it should be Community Wiki? – Jon Skeet Aug 29 '18 at 20:09
  • I don't see why having *iterators* implement `Iterable` by returning `this` would make the code in the answer fail to output the collection twice. The code in the question calls `iterator()` on `strings` (an `Iterable`) twice, not on an iterator. JavaScript's iterators actually do implement iterable (the built-in ones do anyway, you can write one that doesn't), and in exactly the way the OP suggested: They just return `this`. It's handy for skipping the first couple of entries (for instance) before going into a `for-of` loop (JavaScript's version of the enhanced `for`). – T.J. Crowder Apr 13 '21 at 18:06
  • @T.J.Crowder: I agree, it calls `iterator()` twice... but when that returns a reference to the same object twice, how can the two iterators be independent? Or are you suggesting it's fine for the `iterator()` method to basically behave completely differently based on whether it's called on a "normal" `Iterable` or an "`Iterator` that also implements `Iterable`"? That doesn't sound like a good idea to me. My `iterateOver` method should be able to work with any `Iterable`... which means each `iterator()` call creating an independent iterator. – Jon Skeet Apr 13 '21 at 18:10
  • @JonSkeet - The latter. `Iterable.iterator` would always return a new object as it does now (needs the state you mention), but `Iterator.iterator` would return `this`. So calling `iterator` on `strings` (the `Iterable`) returns a new `Iterator` each time you call it. But if you call `iterator` on that `Iterator`, it returns `this`. Which makes it compatible with the enhanced `for` loop. Here's the equivalent JavaScript situation: https://jsfiddle.net/tjcrowder/kf19vpam/ It works really well in JS-land. I take your point about it being different behavior, but it's quite handy... – T.J. Crowder Apr 13 '21 at 18:21
  • ...and classes *already* decide what they mean by being iterable. Another approach to it would be to make it return a new iterator starting where it is in the sequence (a clone). I wasn't involved in the discussions where they added the current behavior so don't know if they considered doing that. (Discussions of that type are much better documented now than they were before the 2015 spec.) – T.J. Crowder Apr 13 '21 at 18:21
  • (I say this as someone who in 2012 responded to a version of this question -- I didn't realize it was a dupe -- with "That doesn't make any sense." :-D And then I made the semantics argument.) – T.J. Crowder Apr 13 '21 at 18:23
  • @T.J.Crowder: But there isn't an `Iterator.iterator()` method, and I don't *think* Java has the ability to implement the same method name differently for different interfaces. (That may have changed - it's been a while since I wrote Java in earnest). I think if we're proposing new methods, it would make more sense for the enhanced for loop to just work with `Iterator` without calling an `iterator()` method at all. – Jon Skeet Apr 13 '21 at 18:41
  • @JonSkeet - `Iterable` and `Iterator` are just interfaces, the implementations would be on (say) `SomeList` and the usually-private class that implements `SomeList`'s `Iterator`. Re the enhanced `for` loop: Agreed, I've always wondered why it didn't. :-) – T.J. Crowder Apr 13 '21 at 19:24
  • @T.J.Crowder: But this question is suggesting that `Iterator` should extend `Iterable`. If you pass some iterator into my `iterateOver` method (as an iterable), that *should* print the sequence twice... the two calls should return independent iterators IMO... otherwise it's really making the behavior of `Iterable` very hard to predict. I would suggest we call a halt here though... we may well be talking part each other, and Stack Overflow comment threads really aren't the best forum for this. – Jon Skeet Apr 14 '21 at 05:38
  • Well, I think it's probably worth considering some flexibility around that "should." Again, classes (in this case, the iterator class for a collection) define what it means to be `Iterable` for them. The equiv,. of your fn above loops through once if given an iterable that's an iterator in JavaScript. But mostly I was just bothered that people didn't seem to get the OP's idea (**I** originally dismissed this sort of idea as silly without really thinking about it), but has fundamentally been embraced in another -- very large -- arena. :-) Anyway, hope all is well and the drumming's still fun! – – T.J. Crowder Apr 14 '21 at 07:38
  • For everyone reading this, in Python, iterators return themselves when you request an interator. So `iter(iterator) is iterator` *should always be true* if the protocol is followed correctly – juanpa.arrivillaga Nov 24 '21 at 09:57
69

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.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
pauljwilliams
  • 19,079
  • 3
  • 51
  • 79
  • 26
    +1: A collection is iterable. An iterator is not iterable because it's not a collection. – S.Lott May 08 '09 at 10:26
  • 52
    While I agree with the answer, I don't know if I agree with the mentality. The Iterable interface presents a single method: Iterator> iterator(); In whatever case, I should be able to specify an iterator to for-each. I don't buy it. – Chris K Dec 19 '09 at 20:36
  • 25
    @S.Lott nice circular reasoning there. – yihtserns Feb 17 '11 at 04:38
  • 1
    @Zefi: Iterator != Iterable. Doesn't seem circular at all. It's a matter of definition. While it's not defined that way in Python, it is defined that way in Java. – S.Lott Feb 17 '11 at 10:50
  • 6
    @S.Lott you said: Collection is iterable; Iterator is not iterable because it is not a collection. If you don't know, that's what we call circular reasoning. It's like saying: I'm awesome. You're not me so you're not awesome. – yihtserns Feb 18 '11 at 07:29
  • 3
    @Zefi: I can't see the circularity yet. Merely repeating the words isn't helping. "Iterator" has a definition; it is not itself iterable, but works with iterable objects. "Iterable" has a definition. It is not an iterator, but works with iterators. Since "iterator" and "iterable" are not the same thing -- they are not defined using "is-a" -- I can't see the circularity. You're going to have to provide more detail to explain how two different but related concepts are "circular". – S.Lott Feb 18 '11 at 13:49
  • 17
    @S.Lott Last attempt: Collection ∈ Iterable. Iterator ≠ Collection ∴ Iterator ∉ Iterable – yihtserns Feb 19 '11 at 05:19
  • @S.Lott your comment should be an independent answer. It's great; simply the definition. – juanmirocks Jul 27 '11 at 10:20
  • 28
    @S.Lott: Collection is totally irrelevant to this discussion. Collection is just one of many possible implementations of Iterable. The fact that something is not a Collection has no bearing on whether it is an Iterable. – ColinD Jul 28 '11 at 17:48
  • @Zefi: your "awesome" example does match S. Lott's method of arguing in his initial comment, but neither one of them is circular reasoning. I agree somewhat with ColinD that the "Collection" aspect is a bit of a red herring, though it makes some sense in light of "an iterator *generally* points to a single instance in a collection." – LarsH Mar 16 '12 at 20:48
  • 2
    The answer is an attempt to rationalize the bad, antihuman design. Iterable intuitively and usefully means the thing you can iterate over. There is not need to argument for collection or any other shit. Otherwise, if you like, the iterator is a collection also and you can iterate over it. – Val Aug 30 '13 at 11:08
  • @S.Lott "An iterator is not iterable because it's not a collection"? What are you smoking? Iterators are not built for collections. – Navin Sep 21 '15 at 06:49
  • An Iterator is something that abstract the iteration. So, it's an ACTIVE actor. An iterable is something that can be iterated on, it's a PASSIVE subject. So, that's why one can ask an Iterable to have an iterator. This is not "antihuman" design, by separating the two, one can ask many iterators and use them independently. That's because people are looking at them trough a "foreach" lens that they find it odd. (4 years late to the party, I know) – programaths Mar 20 '19 at 15:09
  • "Why does the Iterator interface not extend Iterable?" was the original question. It is not asking how Java defines things, but why. – Jason Young Jun 27 '19 at 20:42
65

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,

Barney
  • 2,786
  • 2
  • 32
  • 34
  • 7
    I agree. Theoretically there could be confusion when getting an iterator, using part of it, and then putting it in a foreach (breaking the "each" contract of foreach), but I don't think that's a good enough reason not to have this feature. – Bart van Heukelom Oct 28 '11 at 09:04
  • We already have updated/enhanced the loop to accept arrays instead of making arrays iterable collection. Can you rationalize this decision? – Val Aug 31 '13 at 14:51
  • I upvoted this reply, and it was a mistake. Iterator is stateful, if you promote iteration over an iterator with the `for(item : iter) {...}` syntax, then it will provoke an error when the same iterator is iterated twice. Imagine that `Iterator` is passed into `iterateOver` method instead of `Iterable` in [this example](http://stackoverflow.com/a/839195/1060693). – Ilya Silvestrov Dec 03 '14 at 06:01
  • 4
    It doesn't really matter whether you use the `for (String x : strings) {...}` or `while (strings.hasNext()) {...}` style: if you try to loop through an iterator twice the second time will yield no results, so I don't see that in itself as an argument against allowing the enhanced syntax. Jon's answer is different, because there he's showing how wrapping an `Iterator` in an `Iterable` would cause problems, as in that case you would expect to be able to reuse it as many times as you liked. – Barney Dec 03 '14 at 07:03
19

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) {
McDowell
  • 107,573
  • 31
  • 204
  • 267
9

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);
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
8

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.

andrew cooke
  • 45,717
  • 10
  • 93
  • 143
  • nice ans but your `returning a fresh Iterator on each call` should be accompanied with **why** i.e to prevent concurrency issue... – Anirudha Jan 06 '13 at 17:56
7

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
}
Steve K
  • 4,863
  • 2
  • 32
  • 41
3

To avoid dependence on java.util package

According to the original JSR, An enhanced for loop for the Java™ Programming Language, the proposed interfaces:

  • java.lang.Iterable
  • java.lang.ReadOnlyIterator
    (proposed to be retrofitted onto java.util.Iterator, but apparently this never happened)

…were designed to use the java.lang package namespace rather than java.util.

To quote the JSR:

These new interfaces serve to prevent the dependency of the language on java.util that would otherwise result.


By the way, the old java.util.Iterable gained a new forEach method in Java 8+, for use with lambda syntax (passing a Consumer).

Here is an example. The List interface extends Iterable interface, as any list carries a forEach method.

List
.of ( "dog" , "cat" , "bird" )
.forEach ( ( String animal ) -> System.out.println ( "animal = " + animal ) );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

I also see many doing this:

public Iterator iterator() {
    return this;
}

But that does not make it right! This method would not be what you want!

The method iterator() is supposed to return a new iterator starting from scratch. So one need to do something like this:

public class IterableIterator implements Iterator, Iterable {

  //Constructor
  IterableIterator(SomeType initdata)
  {
    this.initdata = iter.initdata;
  }
  // methods of Iterable

  public Iterator iterator() {
    return new IterableIterator(this.intidata);
  }

  // methods of Iterator

  public boolean hasNext() {
    // ...
  }

  public Object next() {
    // ...
  }

  public void remove() {
    // ...
  }
}

The question is: would there be any way to make an abstract class performing this? So that to get an IterableIterator one only need to implement the two methods next() and hasNext()

2

I agree with the accepted answer, but want to add my own explanation.

  • Iterator represents the state of traversing, e.g., you can get the current element from an iterator and move forward to the next.

  • 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.

It would be nice if Java for loop accepts both Iterator and Iterable.

Dagang
  • 24,586
  • 26
  • 88
  • 133
1

On a related note, you may find the IteratorIterable adapter in Apache Commons Collections4 useful. Just create an instance from an iterator, and you have the corresponding iterable.

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html

ID: org.apache.commons:commons-collections4:4.0

Fabrizio
  • 109
  • 1
  • 6
1

If you came here in search of a workaround, you can use IteratorIterable. (available for Java 1.6 and above)

Example usage (reversing a Vector).

import java.util.Vector;
import org.apache.commons.collections4.iterators.IteratorIterable;
import org.apache.commons.collections4.iterators.ReverseListIterator;
public class Test {
    public static void main(String ... args) {
        Vector<String> vs = new Vector<String>();
        vs.add("one");
        vs.add("two");
        for ( String s: vs ) {
            System.out.println(s);
        }
        Iterable<String> is
            = new IteratorIterable(new ReverseListIterator(vs));
        for ( String s: is ) {
            System.out.println(s);
        }
    }
}

prints

one
two
two
one
serv-inc
  • 35,772
  • 9
  • 166
  • 188
0

Iterators are stateful, they have a "next" element and become "exhausted" once iterated over. To see where the problem is, run the following code, how many numbers are printed?

Iterator<Integer> iterator = Arrays.asList(1,2,3).iterator();
Iterable<Integer> myIterable = ()->iterator;
for(Integer i : myIterable) System.out.print(i);
System.out.println();
for(Integer i : myIterable) System.out.print(i);
Roland
  • 7,525
  • 13
  • 61
  • 124
0

As an aside: Scala has a toIterable() method in Iterator. See scala implicit or explicit conversion from iterator to iterable

Community
  • 1
  • 1
Catweazle
  • 619
  • 12
  • 25
0

For the sake of simplicity, Iterator and Iterable are two distinct concepts, Iterable is simply a shorthand for "I can return an Iterator". I think that your code should be:

for(Object o : someContainer) {
}

with someContainer instanceof SomeContainer extends Iterable<Object>

dfa
  • 114,442
  • 31
  • 189
  • 228
-1

You can try the following example :

List ispresent=new ArrayList();
Iterator iterator=ispresent.iterator();
while(iterator.hasNext())
{
    System.out.println(iterator.next());
}
rgettman
  • 176,041
  • 30
  • 275
  • 357