Question

My question is: Is it possible to go through a container only by implementing Iterator, i.e. without implementing Iterable?

Is it possible to do this:

//From somewhere
Container c = new Container();
//I add elements to the list in the c object.

for(String s : c){
    //Warning: It is not applicable for this expression...
}


class Container implements Iterator<String>{
    //Here I implement a single linked list

    //Here I implement all of the methods of Iterator
}
Was it helpful?

Solution

Even though this kind of design is nothing but ridiculous, and just to entertain your question, you can write this:

public class Container implements Iterable<String>, Iterator<String> {
  @Override public Iterator<String> iterator() { return this; }

  ... everything else you envision for your class ...
}

Then you'll be able to use

for (String s : container)

You may write this as a learning experience, but I strongly advise you never to try it on a real project. The main reason against it is the expectation on the iterator method to always return a fresh, independent iterator, while this implementation achieves the opposite. To give a specific example, imagine someone needing to iterate over the Cartesian product of your container with itself:

for (String s1 : container)
  for (String s2 : container) 
     processPair(s1, s2);

Every Java programmer will tell you that, beyond any doubt, processPair will be called with each possible pair from the container. The behavior they would instead see from your class would make their heads spin. If a bug in production was ever traced to this implementation, your teammates would... let's just say they wouldn't appreciate it.

OTHER TIPS

There is logical difference between Iterable and Iterator.

  • Iterable is the collection or data structure that can be iterated upon. It is a data holder.

  • Iterator is the object that defines the iteration logic (in what way and order to loop trough the elements of the Iterable). It can (and most of the times should) be separate from the logic of the data structure or collection. The purpose is to be able to define more than one Iterator implementation for the same Iterable.
    An important point that I missed, but is present in the other answers, is to keep the loop state away from the iterable object. This allows to loop simultaneously trough the same collection, since each loop will work with a separate iterator instance.

A simple example would be to write two iterators to ArrayList, one looping forwards and another backwards. You only need to create the Iterator implementations over an existing class (ArrayList) without the need of modifying the latter. So, it is possible to implement only an iterator.

The for loop construct in the Java language, however, has been designed to work with iterables. The code:

for (Object o : collecton) { 
    ...
}

is translated by the compiler to something like:

Iterator i = collection.iterator();
while (i.hasNext()) {
  ....
}

Therefore, iterator itself cannot be used wit the for loop in the standard way. Alternatively you can use it like this:

for (Iterator i = collection.iterator(); i.hasNext(); ) {
    Object current = i.next();
    ....
}

What about two successive iterations over the container:

  • By implementing directly Iterator, since variable's Iterator would be shared by all clients, you wouldn't be able to iterate easily through your collection more than once...

  • By defining a method Iterator: (like the one on AbstractList):

    public Iterator iterator() { return new Itr(); //new instance each time }

    Creating a new instance of Iterator each time allows you to iterate as many times as you want over it. (of course, preferably not simultanously).

Moreover, it avoids you to violate Single Responsibility principle, since the way of iterating over a container represents another goal than "defining" the container.

Even if you have your class implements Iterator<T> in order to get it iterator() you have to implement iterable and return your iterator

public class MyCollection<E> implements Iterable<E>{

    public Iterator<E> iterator() {
        return new MyIterator<E>();
    }
}

And here is the corresponding implementation skeleton of the MyIterator class:

public class MyIterator <T> implements Iterator<T> {

    public boolean hasNext() {

        //implement...
    }

    public T next() {
        //implement...;
    }

    public void remove() {
        //implement... if supported.
    }
}

In order to use enhanced for-loop (a.k.a fancy for-loop) you have to implement Iterable not Iterator

Of course you can implement Iterator, in that case Your container will be itsef an Iterator

public class Cont<T> implements Iterator<T> {

    @Override
    public boolean hasNext() {
        // TODO implment
        return false;
    }

    @Override
    public T next() {
        // TODO implment
        return null;
    }

    @Override
    public void remove() {
        // TODO implment
    }

}

and you can use it like that:

public static void main(String... args) {
    Cont cont = new Cont<SomeType>();
    while(cont.hasNext()) {
        SomeType obj = cont.next();
    }
}

The usual case is to Implment Iterable, so you can use all language features available for it. Implement an Iterator if you are coding a Collection or you want to have some logic inside some of its methods, for instance lazy loading inside the next() method.

If you want to use simple for-each statement - No. You need to call Iterator<E> object from Iterable<E> object using iterator() method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top