“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
Contents
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.