Is it generally considered bad practice to provide Iterator
implementations that are "infinite"; i.e. where calls to hasNext()
always(*) return true?
Typically I'd say "yes" because the calling code could behave erratically, but in the below implementation hasNext()
will return true unless the caller removes all elements from the List that the iterator was initialised with; i.e. there is a termination condition. Do you think this is a legitimate use of Iterator
? It doesn't seem to violate the contract although I suppose one could argue it's unintuitive.
public class CyclicIterator<T> implements Iterator<T> { private final List<T> l; private Iterator<T> it; public CyclicIterator<T>(List<T> l) { this.l = l; this.it = l.iterator(); } public boolean hasNext() { return !l.isEmpty(); } public T next() { T ret; if (!hasNext()) { throw new NoSuchElementException(); } else if (it.hasNext()) { ret = it.next(); } else { it = l.iterator(); ret = it.next(); } return ret; } public void remove() { it.remove(); } }
(Pedantic) EDIT
Some people have commented how an Iterator
could be used to generate values from an unbounded sequence such as the Fibonacci sequence. However, the Java Iterator
documentation states that an Iterator is:
An iterator over a collection.
Now you could argue that the Fibonacci sequence is an infinite collection but in Java I would equate collection with the java.util.Collection
interface, which offers methods such as size()
implying that a collection must be bounded. Therefore, is it legitimate to use Iterator
as a generator of values from an unbounded sequence?
No, they're not bad, they're actually useful. It depends whether you left some part of the code that eats up memory as the infinite loop proceeds. Infinite loops are used at almost everything: video games, networking, machine learning, etc.
Iterator and for-each loop are faster than simple for loop for collections with no random access, while in collections which allows random access there is no performance change with for-each loop/for loop/iterator.
iterators are not reusable; you need to get a fresh Iterator from the Iterable collection each time you want to iterate over the elements.
Iterator Advantage: Ability to remove elements from Collections. Ability to move forward and backward using next() and previous() . Ability to check if there more elements or not by using hasNext() .
I think it is entirely legitimate - an Iterator
is just a stream of "stuff". Why should the stream necessarily be bounded?
Plenty of other languages (e.g. Scala) have the concept of unbounded streams built in to them and these can be iterated over. For example, using scalaz
scala> val fibs = (0, 1).iterate[Stream](t2 => t2._2 -> (t2._1 + t2._2)).map(_._1).iterator fibs: Iterator[Int] = non-empty iterator scala> fibs.take(10).mkString(", ") //first 10 fibonnacci numbers res0: String = 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
EDIT: In terms of the principle of least surprise, I think it depends entirely on the context. For example, what would I expect this method to return?
public Iterator<Integer> fibonacciSequence();
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