How to Use Java Iterators

java iterator

An iterator in Java provides the means to access elements of a collection one-by-one in a sequential, unidirectional and non-repeatable manner. This is useful in cases when the size of the collection is not known beforehand or when the collection does not expose suitable methods to access a contained element at a specific position. Iterators form a part of the core Java implementation and are defined as derivatives of the Iterator entity present within the java.util package.

A Java collection iterator has the following properties:

  • Sequential: The elements are retrieved using the iterator in the same order in which they are present in the collection.
  • Unidirectional: The iterator can proceed in one direction only, usually from left to right. However, certain derivatives of the iterator (e.g. the ListIterator) allows for bi-directional movement.
  • Non-repeatable: Once a traversal is complete, the same iterator cannot be utilized a second time to repeat the loop and therefore, you need to obtain a new iterator instance to repeat the process.

Learn advanced Java using a tutorial at Udemy.com

Definition and Usage

The usual practice is to define the iterator as an interface with a generic set of methods. The following code snippet describes the usual way that an iterator is obtained for a given collection:

Collection col = <some collection object, e.g. ArrayList, LinkedList, etc.>
Iterator iter = col.iterator();

All classes that implement the java.util.Collection interface must also provide a corresponding implementation of the Iterator interface that is accessible using the iterator() method. The exact semantics of the Iterator for a given collection is hidden from the API user by following the principles of encapsulation.

Once you obtain a reference to an iterator instance for a collection, you can use it to browse elements in the collection, as shown by the code below:

while(iter.hasNext()) {

Object element = iter.next();

}

Method Summary

The above example brings to light the two most important methods of the iterator interface:

  • booleanhasNext()

Internally, each iterator instance maintains a pointer to the element in the collection that will be accessed next by the iterator. The hasNext() methods is a check to see if the next element in the collection is available for access. If the collection is empty or the end of the collection has been reached, this method should return false as the next element is not available.

  • Object next()

This method actually returns the next element from the collection associated with the iterator. If the next element is not available, a NoSuchElementException error is thrown.

Loops and Conditional Blocks

Note that since the iterator does not expose any positional information (e.g. the index of the next element in the collection), you cannot use the iterator in a “for” loop. You can use the iterator in an “if” block in cases when the corresponding collection is expected to have only one element or you are interested in only the first element of the collection:

Iterator iter = getIteratorFromSomeMethod();

if(iter.hasNext()) {

Object element = iter.next();

}

This is especially true if the iterator is obtained as the result of executing a method that does not provide the corresponding collection for regular access, as shown in the example above. Other elements in the collection are either not present or are not deemed relevant and therefore discarded.

Learn Java programming from scratch at Udemy.com

Usage of Generics

In the above code snippet, the next element obtained from the iterator is of the generic Object type. You must typecast it to a specific object type in order to be able to use it appropriately. This is as shown in the code example below:

Collection col = <some collection object, e.g. ArrayList, LinkedList, etc. of say java.util.Date objects>

Iterator iter = col.iterator();

while(iter.hasNext()) {

Object obj = iter.next();

Date d = (Date) obj;

/* Do something with the date object */

}

Starting with JRE 5.0, Java supports generics as part of the core language feature. Using generics, the above typecast mechanism can be avoided for a more defined (and therefore error free) construct as shown below:

Collection<Date> col = <some collection object, e.g. ArrayList, LinkedList, etc. of say java.util.Date objects>

Iterator<Date>iter = col.iterator();

while(iter.hasNext()) {

Date d = iter.next();

/* Do something with the date object */

}

Note the absence of the typecast operation in the above example.

Differences with the Enumeration Entity

The iterator was introduced as part of the Java Collections Framework only since version 1.2 of the language. Prior to this version, the core language features included, and still includes, the java.util.Enumeration entity. Syntactically, the iterator and the enumeration are identical, but the exceptions are:

  1. The iterator includes an additional method called remove() that can remove the next element from the underlying collection.
  2. All collection objects must define and expose an iterator instance. The same is not true of the Enumeration class.

Variation in Capabilities

Some iterator instances may provide additional features and capabilities above and over the generic capabilities of unidirectional and sequential access to collection elements. A good example is the ListIterator that is associated with Collections of type java.util.List and exposes the following additional capabilities:

  • The ability to traverse both forward and backward within the collection.
  • The ability to insert new elements to the collection.
  • The ability to access the position of a specific element in the collection.

Concurrent Modifications

One of the common sources of errors in Java programs is when a code attempts to modify a collection, either by adding a new element or removing an existing element while a traversal is in progress. This is as shown in the example below:

List<String> list = new ArrayList<String>();

for(inti=0; i<list.size(); i++) {

if(list.get(i).equals("xyz")) {

list.remove(i);

}

}

This will throw a ConcurrentModificationException error when the remove() method is called. In such cases, an iterator can be used to safely remove an existing element while traversal is in progress.

List<String> list = new ArrayList<String>();

Iterator<String>iter = list.iterator();

while(iter.hasNext()) {

if(iter.next().equals("xyz")) {

iter.remove();

}

}

New to Java? Take a course at Udemy.com to learn how to work with iterators.

No error condition is encountered during element removal using the iterator’s remove() method.