Why do I need to call previous() twice in ListIterator so I can go in 'reverse' iteration?

Viewed 191

We know what ListIterator has method next() and previous() that allow us to traverse in both directions. So I made a little program to try it out.

List<String> songs = new ArrayList<>();
   songs.add("song1");
   songs.add("song2");
   songs.add("song3");
   songs.add("song4");

    ListIterator<String> iterator = songs.listIterator();

    System.out.println(iterator.next());
    System.out.println(iterator.next());
    System.out.println(iterator.next());

    System.out.println(iterator.previous());
    System.out.println(iterator.previous());

What I was expecting is to get:

song1
song2
song3
song2
song1

But I was wrong. Actual result it this:

song1
song2
song3
song3
song2

Can someone tell me how does this happens? Isn't cursor when I am 'in' song3 literally there, so when I do previous() it gives me song before that one? How can I finally understand this concept the easy way?

2 Answers

Because as the docs says next() gives you the current element AND moves the iterator to the next:

Returns the next element in the list and advances the cursor position.

This when it prints song3 the cursor is moved just after song3, then if you call previous() you will get the element just before the cursor, hence song3 again.

Take a look at ListIterator's javadoc...

                     Element(0)   Element(1)   Element(2)   ... Element(n-1)
cursor positions:  ^            ^            ^            ^                  ^

At the beginning of an iteration, cursor points before the first element.

A call to next() (1) retrieves the first element after the cursor position and (2) advances the cursor to point after the retrieved element.

A call to previous() (1) retrieves the first element before the cursor position and (2) sets the cursor to point before the retrieved element.


Lets examine what happens between your 3rd and 4th line of output that is problematic.

State of your iterator after the second line of output:

                    "song1"   "song2"   "song3"   "song4"
cursor position:                      ^

Now you call next() again and output "song3". Your iterator state looks like this:

                    "song1"   "song2"   "song3"   "song4"
cursor position:                                ^

At this point you call previous() and "song3" gets printed again. The iterator state after the operation is as follows:

                    "song1"   "song2"   "song3"   "song4"
cursor position:                      ^
Related