Using an Explicit Iterator on a Collection – Collections: Part II
Using an Explicit Iterator on a Collection
A collection provides an iterator which allows sequential access to the elements of a collection. An iterator can be obtained by calling the iterator() method of the Collection<E> interface. An iterator is defined by the generic interface java.util.Iterator<E> that has the following methods:
boolean hasNext()
From
Iterator<E>
interface.
Returns true if the underlying collection still has elements left to return. A future call to the next() method will return the next element from the collection.
E next()
From
Iterator<E>
interface.
Moves the iterator to the next element in the underlying collection, and returns the current element. If there are no more elements left to return, it throws a NoSuchElementException.
void remove()
Optional From
Iterator<E>
interface.
Removes the element that was returned by the last call to the next() method from the underlying collection. Invoking this method results in an Illegal-StateException if the next() method has not yet been called, or when the remove() method has already been called after the last call to the next() method. This method is optional for an iterator—that is, it throws an Unsupported-OperationException if the remove operation is not supported.
default void
forEachRemaining(Consumer<? super E> action)
From
Iterator<E>
interface.
The specified action is performed on each of the remaining elements in the collection associated with an iterator, unless an exception is thrown during its execution. The functional interface Consumer<T> is covered in §13.7, p. 709.
After obtaining the iterator for a collection, the methods provided by the Iterator<E> interface can be used systematically to iterate over the elements of the underlying collection one at a time.
In Example 15.1, an explicit iterator is obtained at (2) and used in the loop at (3) to iterate over all elements in the underlying collection. A call to the hasNext() method in the condition of the loop ensures that there is still an element to retrieve from the collection. At (4) the current element is retrieved by the iterator from the collection by calling the next() method. No casts are necessary at (4), as the compiler guarantees that the iterator will return a String object from the underlying collection.
Iterator<String> iterator = collectionOfNames.iterator(); // (2)
while (iterator.hasNext()) { // (3)
String name = iterator.next(); // (4)
System.out.print(name.toUpperCase() + ” “);
}
Note that the methods are invoked on the iterator, not the underlying collection. In Example 15.1, the hasNext() method is called before the next() method to ensure that there is still an element remaining to be processed; otherwise, a java.util.NoSuchElementException can be raised at runtime. Using an explicit iterator puts this responsibility on the user code.
In Example 15.1, we used an iterator in a while loop at (3) for iterating over the collection. It is quite common to use an iterator in a for(;;) loop for this purpose, where the iterator is obtained in the initialization part, and the increment part is left empty:
for (Iterator<String> iterator = collectionOfNames.iterator();
iterator.hasNext(); /* Empty increment. */) {
String name = iterator.next();
System.out.print(name.toUpperCase() + ” “);
}
The majority of the iterators provided in the java.util package are said to be fail-fast. When an iterator has already been obtained, structurally modifying the underlying collection by other means will invalidate the iterator. Subsequent use of this iterator will throw a ConcurrentModificationException, as the iterator checks to see if the collection has been structurally modified every time it accesses the collection. The remove() method of an iterator is the only recommended way to delete elements from the underlying collection during iteration with an iterator (p. 796).
The order in which the iterator will return the elements from an underlying collection depends on the iteration order supported by the collection. For example, an iterator for a list will iterate over the elements in the sequential order they have in the list, whereas the iteration order for the elements in an ordinary set is not predetermined. An iterator for a sorted collection will make the elements available in a given sort order. Iteration order will be discussed together with the individual concrete collection classes.