Logic of the ArrayList iterator

I can't wrap my head around the logic of iterators. Here, for example, is such a program:

import java.util.*;

public class RememberingJava {

    public static void main(String[] args) {
        ArrayList<String> numbers = new ArrayList<>();
        numbers.add("0");
        numbers.add("1");
        numbers.add("2");

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

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        System.out.println();

        iterator.set("111");
        while (iterator.hasPrevious()) {
            System.out.println(iterator.previous());
        }
    }
}

What happens after filling in the list?

According to my logic: an iterator is created that points to the element "0". Then, since there is a "1" after "0"," 0 "is output, and the iterator goes to"1". After "1" there is "2", so "1" is output, and the iterator goes to "2". But after "2" there is nothing.

Question - why "2" is output, and why after output "2" the iterator remains on it (judging by the fact that the element storing " 2 " is normally assigned "111", the iterator after all remained on "2")?

Author: Regent, 2018-09-19

4 answers

Initially, the iterator does not point to anything, it seems to point to the place before the first element of the list. If the next() method is called on the iterator at this point, and the list is empty, an exception Exceptionjava.util.NoSuchElementException will be thrown. If you call hasNext() beforehand, the latter will return false, thus the construction

   while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }

It will work correctly regardless of whether there is something in the list or not -- in the case of an empty loop, the body will simply not be executed once, since the loop condition (iterator.hasNext()) from the beginning, it will be false.

Next, if the list contains at least one element, the iterator.hasNext() method returns true. The meaning of this method is precisely determined by its name-literally translated, it means "There is another one". We can call this method as much as we want, the state of the iterator does not change from it -- the iterator still points to the "place before the first one". In this case, the first (i.e. zero, with index 0) element of the list is next to the current position of the iterator, so that the next() method will return this "next" (null) element. The next() method, unlike the hasNext() method, changes the state of the iterator -- shifts it by one position, so that after that hasNext() will report whether there is a second element in the list(i.e., again the next one in relation to the read one), and the next call to next() will return this second element and change the position of the iterator again. If the read item is the last item in the list, then hasNext() will then return false, and our loop will not be able to continue working.

After reading element "2" in your example, the iterator continues to point to it, because after reading it, you no longer called next() (and if you did, you would get an exception, because there is no element following it). So, indeed, calling iterator.set("111") replaces the last item in the list with a reference to the new line "111". This is as it should be -- the documentation teaches that

Void set(E e) -- Replaces the last element returned by next() or previous() with the specified element (optional operation).

 3
Author: m. vokhm, 2018-09-19 18:10:45
  1. The listIterator method creates a new iterator whose field cursor is zero
  2. The hasNext method compares the current value of cursor with the number of items in the list. If they don't match, the method returns true
  3. The next method returns an element with the index cursor and increments the value of cursor by one. The method also stores the index of the returned element in the field lastRet

As a result, after the first cycle, cursor equals 3, and lastRet equals 2

Method set uses lastRet, not cursor, so it is the third element of the list that changes

  1. The hasPrevious method compares cursor to zero. If not equal, returns true
  2. The previous method returns an element with the index cursor - 1 and reduces the value of cursor by one. The method also stores the index of the returned element in the field lastRet
 2
Author: Regent, 2018-09-19 18:10:34

In fact, when creating an iterator, it does not point to the first element of the collection, it only knows that the first time the next() method is called, it will point to the first element, if there is one. In other words, the iterator seems to be in an undefined state until the first call to next(). Well, the logic of his actions will be as follows:

iterator = numbers.listIterator(); // положение итератора не определёно
 // 1-й цикл
iterator.hasNext() // true
iterator.next()) // 0
 // 2-й цикл
iterator.hasNext() // true
iterator.next()) // 1
 // 3-й цикл
iterator.hasNext() // true
iterator.next()) // 2
 // 4-й цикл
iterator.hasNext() // false

After that, the iterator is on the last element.

 1
Author: Serodv, 2018-09-19 17:41:16
  1. An iterator is created, which is located before the first element
  2. there is something after the iterator, i.e. "0" - the iterator moves to it and outputs " 0 "
  3. after "0" there is something-the iterator moves to "1" and outputs "1"
  4. after "1" there is something-the iterator moves to "2" and outputs "2"
  5. an empty string is output
  6. the element on which the iterator stands, i.e. "2", is set to " 111 "
  7. there is something before "111" - output "111" and shifting the iterator to "1"
  8. there is something before "1" - output "1" and shift the iterator to " 0 "
  9. before "0" is the beginning of the iterator-output "0" and move the iterator to the beginning.

TOTAL: The up and down iterator moves differently:

  • when moving up, the iterator is raised first, then the current element is output.
  • when moving down, the current element is displayed first, then the iterator is lowered.
 1
Author: , 2018-09-19 18:35:01