Java notes -- Iterator

1, Definition

Java Iterator (iterator) is not a collection. It is a method for accessing a collection. It can be used to iterate over collections such as ArrayList and HashSet.

Iterator is the simplest implementation of Java iterator. ListIterator is the interface in the Collection API, which extends the iterator interface.

The three basic operations of iterator it are next, hasNext, and remove.

  • Call it Next () returns the next element of the iterator and updates the state of the iterator.
  • Call it Hasnext() is used to detect whether there are still elements in the collection.
  • Call it Remove() deletes the element returned by the iterator.

2, Instance

Get an iterator
To get an iterator from a collection, you can use the iterator() method:

// Introducing ArrayList and Iterator classes
import java.util.ArrayList;
import java.util.Iterator;

public class RunoobTest {
    public static void main(String[] args) {

        // Create collection
        ArrayList<String> sites = new ArrayList<String>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Zhihu");

        // Get iterator
        Iterator<String> it = sites.iterator();

        // The first element in the output collection
        System.out.println(it.next());
    }
}

Execute the above code and the output results are as follows:

Google

Circular set element
The easiest way to have the iterator it return all the elements in the collection one by one is to use the while loop:

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

The following output sets all elements in sites:

// Introducing ArrayList and Iterator classes
import java.util.ArrayList;
import java.util.Iterator;

public class RunoobTest {
    public static void main(String[] args) {

        // Create collection
        ArrayList<String> sites = new ArrayList<String>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Zhihu");

        // Get iterator
        Iterator<String> it = sites.iterator();

        // All elements in the output collection
        while(it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

Execute the above code and the output results are as follows:

Google
Runoob
Taobao
Zhihu

Delete element

To delete an element in a collection, you can use the remove() method.

In the following example, we delete elements less than 10 in the collection:

// Introducing ArrayList and Iterator classes
import java.util.ArrayList;
import java.util.Iterator;

public class RunoobTest {
    public static void main(String[] args) {
        ArrayList<Integer> numbers = new ArrayList<Integer>();
        numbers.add(12);
        numbers.add(8);
        numbers.add(2);
        numbers.add(23);
        Iterator<Integer> it = numbers.iterator();
        while(it.hasNext()) {
            Integer i = it.next();
            if(i < 10) {  
                it.remove();  // Delete elements less than 10
            }
        }
        System.out.println(numbers);
    }
}

Execute the above code and the output results are as follows:

[12, 23]

3, Compare with Foreach

Iterate through the collection using the iterator:

  public static void main(String[] args) {
      List<String> list = new ArrayList<String>();
        list.add("Zhang San 1");
        list.add("Zhang San 2");
        list.add("Zhang San 3");
        list.add("Zhang San 4");
        
        List<String> linkList = new LinkedList<String>();
        linkList.add("link1");
       linkList.add("link2");
       linkList.add("link3");
       linkList.add("link4");
       
       Set<String> set = new HashSet<String>();
       set.add("set1");
       set.add("set2");
       set.add("set3");
       set.add("set4");
       //Traversing the ArrayList collection using iterators
       Iterator<String> listIt = list.iterator();
       while(listIt.hasNext()){
           System.out.println(listIt.next());
       }
       //Use iterators to traverse the Set collection
       Iterator<String> setIt = set.iterator();
       while(setIt.hasNext()){
           System.out.println(listIt.next());
       }
       //Traversing the LinkedList collection using an iterator
       Iterator<String> linkIt = linkList.iterator();
       while(linkIt.hasNext()){
           System.out.println(listIt.next());
       }
 }

Traverse the collection using foreach:

List<String> list = new ArrayList<String>();
list.add("Zhang San 1");
list.add("Zhang San 2");
list.add("Zhang San 3");
list.add("Zhang San 4");
for (String string : list) {
    System.out.println(string);
}

It can be seen that the advantage of using foreach to traverse the set is that the code is more concise, less error prone, and don't care about the start and end values of subscripts.

4, Iterator traversal cannot delete elements in the collection

When using Iterator, it is forbidden to change the size structure of the traversed container. For example, when iterating with Iterator, if add and remove operations are performed on the collection, a ConcurrentModificationException exception will appear.

  List<String> list = new ArrayList<String>();
  list.add("Zhang San 1");
  list.add("Zhang San 2");
  list.add("Zhang San 3");
  list.add("Zhang San 4");
 
  //Traversing the ArrayList collection using iterators
  Iterator<String> listIt = list.iterator();
  while(listIt.hasNext()){
     Object obj = listIt.next();
     if(obj.equals("Zhang San 3")){
         list.remove(obj);
     }
 }

Because before you iterate, the Iterator has been passed through the list Itertor () is created. If you change the container size of the list during the iteration, Java will give an exception. Because the Iterator object cannot actively synchronize the changes made by the list at this time, Java will think that such an operation is thread unsafe and will give a friendly reminder (throw a ConcurrentModificationException)
Implementation source code of Iterator:

  private class Itr implements Iterator<E> {
      int cursor;       // index of next element to return
      int lastRet = -1; // index of last element returned; -1 if no such
      int expectedModCount = modCount;
  
      public boolean hasNext() {
         return cursor != size;
      }
  
     @SuppressWarnings("unchecked")
     public E next() {
         checkForComodification();
         int i = cursor;
         if (i >= size)
             throw new NoSuchElementException();
         Object[] elementData = ArrayList.this.elementData;
         if (i >= elementData.length)
             throw new ConcurrentModificationException();
         cursor = i + 1;
         return (E) elementData[lastRet = i];
     }
 
     public void remove() {
         if (lastRet < 0)
             throw new IllegalStateException();
         checkForComodification();
 
         try {
             ArrayList.this.remove(lastRet);
             cursor = lastRet;
             lastRet = -1;
             expectedModCount = modCount;
         } catch (IndexOutOfBoundsException ex) {
             throw new ConcurrentModificationException();
         }
     }
 
     final void checkForComodification() {
         if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
     }
 }

By looking at the source code, it is found that the checkForComodification() method originally checked and threw an exception. In ArrayList, modCount is the version number of the current collection, and 1 will be added each time the collection is modified (added or deleted); expectedModCount is the version number of the current Iterator, which is initialized to modCount when the Iterator is instantiated. We can see that in the checkforconfirmation () method, you are verifying whether the value of modCount and expectedModCount are equal, so when you call ArrayList Add() or ArrayList When remove(), only the status of modCount is updated, and the expectedModCount in the Iterator is not synchronized, so it will cause the Iterator to be called again An exception was thrown when the next() method was. But why use Iterator Is there no problem with remove()? It is found in line 32 of the source code that the value of expectedModCount is synchronized in the remove () of the Iterator, so the next time you call next(), the check will not throw an exception.
The main purpose of using this mechanism is to realize the fail fast mechanism in ArrayList. There is a fast failure mechanism in a large part of Java collections.
Conditions generated by the quick failure mechanism: when multiple threads operate on the Collection, if one thread traverses the Collection through the Iterator and the content of the Collection is changed by other threads, a ConcurrentModificationException will be thrown.
Therefore, to ensure that there are no errors when using Iterator to traverse the set, we should ensure that there will be no structural changes to the set in the process of traversing the set.
When using Foreach, an exception occurs when modifying the structure of the collection:
As mentioned above, classes that implement the iteratable interface can be traversed through foreach because foreach depends on the Iterator object returned by the iteratable interface. In essence, foreach is actually using iterators to modify the structure of the collection when traversing with foreach, It is essentially the same as modifying the collection structure when traversing with Iterator. Therefore, the same exception will be thrown to implement the rapid failure mechanism.
Foreach is jdk1 A new loop structure, foreach, is added to simplify the behavior of traversing the set.
Comparison between for loop and iterator:
* each has its own advantages in efficiency:

  • ArrayList is faster for random access, and the get() method used in the for loop is the random access method, so the for loop in ArrayList is faster.
  • LinkedList uses sequential access, and the next() method in Iterator uses sequential access, so it is faster to use Iterator in LinkedList.
  • It is mainly judged according to the data structure of the set.

5, Compare with ListIterator

From the above definition, we can deduce ListIterator:

(1) Two way movement (forward / backward traversal)

(2) Generates an index of the previous and subsequent elements relative to the current position pointed to by the iterator in the list

(3) You can use the set() method to replace the last element it has accessed

(4) You can use the add() method to insert an element before the element returned by the next() method or after the element returned by the previous() method

Use example:

import java.util.*;
public class TestListIterator{
 
    public static void main(String[] args) {
        ArrayList<String> a = new ArrayList<String>();
        a.add("aaa");
        a.add("bbb");
        a.add("ccc");
        System.out.println("Before iterate : " + a);
        ListIterator<String> it = a.listIterator()
        while (it.hasNext()) {
            System.out.println(it.next() + ", " + it.previousIndex() + ", " + it.nextIndex());
        }
        while (it.hasPrevious()) {
            System.out.print(it.previous() + " ");
        }
        System.out.println();
        it = a.listIterator(1);//Call the listIterator(n) method to create a ListIterator that initially points to an element with a list index of n.
       while (it.hasNext()) {
            String t = it.next();
            System.out.println(t);
            if ("ccc".equals(t)) {
                it.set("nnn");
            } else {
                it.add("kkk");
            }
        }
       System.out.println("After iterate : " + a);//[aaa, bbb, kkk, nnn]
    }
}

Difference between Iterator and ListIterator
When we use List and Set, we often use Iterator (Iterator) in order to traverse its data. Using an Iterator, you don't need to interfere with its traversal process, just take out one data you want at a time for processing. But there are also differences in use. Both List and Set have iterators () to get their iterators. For a List, you can also obtain its iterators through list iterator(). The two iterators are not universal in some cases. The main differences between Iterator and ListIterator are as follows:

(1) ListIterator has an add() method to add objects to the List, but Iterator cannot
(2) Both ListIterator and iterator have hasNext() and next() methods, which can realize sequential backward traversal, but ListIterator has hasPrevious() and previous() methods, which can realize reverse (sequential forward) traversal. Iterator can't.
(3) ListIterator can locate the current index position, and nextIndex() and previousIndex() can be implemented. Iterator does not have this feature.
(4) Can delete objects, but ListIterator can modify objects, and set() method can. Iierator can only traverse and cannot be modified.

Because of these functions of ListIterator, you can operate List data structures such as LinkedList. In fact, array objects can also be implemented with iterators.

Keywords: Java

Added by yuraupt on Mon, 17 Jan 2022 06:23:56 +0200