tags:

views:

1875

answers:

6

Why does the Iterator interface not extend 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.listSomObjects()) {
....
}

where listSomeObject returns an iterator.

+11  A: 

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.

Visage
+1: A collection is iterable. An iterator is not iterable because it's not a collection.
S.Lott
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 Kaminski
+24  A: 

An iterator is stateful. The idea is that if you call Iterable.iterator() twice you'll get independent iterators. 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
I think that you have confused in with :, in C# :)
dfa
Doh, thanks. Mind you, I was only half there - I didn't call it foreach.
Jon Skeet
It's entirely implementation dependent whether you'll get independent iterators. You have no way of ensuring they are.
Chris Kaminski
@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
+4  A: 

An Iterable is a thing from which you obtain an Iterator.

skaffman
Exactly. Iterable is a factory method for Iterators. See also http://stackoverflow.com/questions/27240/why-arent-enumerations-iterable/38518#38518
erickson
+1  A: 

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
A: 

Visage allready said that these are both different concepts introduced in different versions of Java. Iterator was introduced first, that's only one of the reasons it doesn't extend Iterable.

But nothing can keep you from implementing both interfaces in one class. In fact this is the solution I see programmers use very often.

public class MyClass implements Iterator, Iterable {

    // methods of Iterable

    public Iterator iterator() {
        return this;
    }

    // methods of Iterator

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

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

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

}
Richard Metzler
+1  A: 

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(IterableIterator iter)
  {
    this.initdata = iter.initdata;
  }
  // methods of Iterable

  public Iterator iterator() {
    return new MyClass(this.somedata);
  }

  // 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 classes next() and hasNext()

Martin Vatshelle