Using Java ArrayList’s List Iterator

A ListIterator allows traversal of a Java ArrayList in forward or backward direction.

“A man devoid of hope and conscious of being so has ceased to belong to the future.”
― Albert Camus, The Myth of Sisyphus and Other Essays

1. Introduction

Java’s ArrayList class provides a list iterator which allows, among other things, traversal of the list in either direction. This is in comparison to a normal Iterator that allows traversal of the list in forward direction only. In this article, we delve into the usage and behavior of the ListIterator when used with an ArrayList.

2. Forward Iteration with an Iterator

A ListIterator is created using the method listIterator() and can be used for forward iteration using the methods hasNext() and next(). These methods are defined by the Iterator interface.

ArrayList<String> alist = new ArrayList<>(Arrays.asList("apple",
                                                        "orange",
                                                        "banana",
                                                        "grapes",
                                                        "melon"));
System.out.println("t1 => " + alist);
ListIterator<String> li = alist.listIterator();
System.out.print("t2 => [");
while (li.hasNext()) {
    String item = li.next();
    System.out.print(item + ", ");
}
System.out.println("]");
# prints
t1 => [apple, orange, banana, grapes, melon]
t2 => [apple, orange, banana, grapes, melon, ]

3. Index of the Next Element

An addition that ListIterator offers over the Iterator is the you can retrieve the index of the next element in the list using the method nextIndex(). Note that the returned index refers to the element that will be returned by the call to next().

while (li.hasNext()) {
    int index = li.nextIndex();
    String item = li.next();
    System.out.print(index + ")" + item + ", ");
}
# prints
t2 => [0)apple, 1)orange, 2)banana, 3)grapes, 4)melon, ]

4. Reverse Iteration

Iterating over an ArrayList in the reverse direction is one of the main advantages of a list iterator. To iterate over all the elements, you need to initialize the list iterator properly to point to just after the last element. One way to do that is to pass the size to the listIterator() method of the ArrayList as follows:

Note that similar to using nextIndex() above, here we use previousIndex() to obtain the index of the element that will be returned by the next call to previous().

ArrayList<String> alist = new ArrayList<>(Arrays.asList("apple",
                                                        "orange",
                                                        "banana",
                                                        "grapes",
                                                        "melon"));
ListIterator<String> li = alist.listIterator(alist.size());
System.out.print("t4 => [");
while (li.hasPrevious()) {
    int index = li.previousIndex();
    String item = li.previous();
    System.out.print(index + ")" + item + ", ");
}
System.out.println("]");
# prints
t4 => [4)melon, 3)grapes, 2)banana, 1)orange, 0)apple, ]

Note that the same ListIterator object can be used for forward and backward iteration. Perhaps at the end of each as the following example demonstrates.

System.out.print("t5 => [");
while (li.hasNext()) {
    int index = li.nextIndex();
    String item = li.next();
    System.out.print(index + ")" + item + ", ");
}
System.out.println("]");
System.out.print("t6 => [");
while (li.hasPrevious()) {
    int index = li.previousIndex();
    String item = li.previous();
    System.out.print(index + ")" + item + ", ");
}
System.out.println("]");
# prints
t5 => [0)apple, 1)orange, 2)banana, 3)grapes, 4)melon, ]
t6 => [4)melon, 3)grapes, 2)banana, 1)orange, 0)apple, ]

5. Removing Elements from the List

The ListIterator provides the method remove() which allows removal of the last element returned by next() or previous().

ListIterator<String> li = alist.listIterator(2);
int index = li.nextIndex();
String item = li.next();
System.out.println("rm => " + index + ")" + item);
li.remove();
li = alist.listIterator();
System.out.print("t7 => [");
while (li.hasNext()) {
    index = li.nextIndex();
    item = li.next();
    System.out.print(index + ")" + item + ", ");
}
System.out.println("]");
# prints
rm => 2)banana
t7 => [0)apple, 1)orange, 2)grapes, 3)melon, ]

6. Replacing Elements in a List

Similar to removing elements using the ListIterator, it is also possible to replace an element using the set() method. The element replaced is the one that was previously returned from next() or previous(). In the sample code below, we replace an element obtained from previous().

ListIterator<String> li = alist.listIterator(2);
int index = li.previousIndex();
String item = li.previous();
System.out.println("set => " + index + ")" + item);
li.set("pear");
li = alist.listIterator();
System.out.print("t8 => [");
while (li.hasNext()) {
    index = li.nextIndex();
    item = li.next();
    System.out.print(index + ")" + item + ", ");
}
System.out.println("]");
# prints
set => 1)orange
t8 => [0)apple, 1)pear, 2)banana, 3)grapes, 4)melon, ]

Note that remove() and set() can be invoked once per invocation of next() (or previous()) only. Invoking these more than once results in an IllegalStateException.

try {
    ListIterator<String> li = alist.listIterator(2);
    int index = li.previousIndex();
    String item = li.previous();
    System.out.println("rm => " + index + ")" + item);
    li.remove();
    li.remove();
} catch(IllegalStateException ex) {
    System.err.println("Exception: " + ex);
}
# prints
rm => 1)orange
Exception: java.lang.IllegalStateException

Review

We have covered most uses of the ListIterator when used with an ArrayList. Using the ListIterator you can traverse forward as well as backward in the list. You can also remove or update the last fetched item from the list.