Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList和 HashSet 等集合。Iterator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口。
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
 
 
迭代器 it 的两个基本操作是 next 、hasNext 和 remove。
 
 
Java中的Iterator功能比较简单,并且只能单向移动:
使用方法iterator()要求容器返回一个Iterator。 注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态。
调用 it.hasNext() 用于检测集合中是否还有元素。
调用 it.remove() 将迭代器返回的元素删除。
Iterator 类位于 java.util 包中,使用前需要引入它,语法格式如下:
import java.util.Iterator; // 引入 Iterator 类1.获取一个迭代器并循环集合元素
集合想获取一个迭代器可以使用 iterator() 方法
package com.joshua317;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
public class Main {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> names = new ArrayList<>();
        String[] namesArr = {"小明","二蛋","joshua317"};
        names.addAll(Arrays.asList(namesArr));
        System.out.println(names);
        //获取迭代器
        Iterator<String> iterator = names.iterator();
        //遍历集合元素,让迭代器 it 逐个返回集合中所有元素最简单的方法是使用 while 循环
        while (iterator.hasNext()) {
            String name = iterator.next();
            System.out.println(name);
        }
    }
} 
 
2.删除集合里面的元素
要删除集合中的元素可以使用 remove() 方法。
package com.joshua317;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
public class Main {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> names = new ArrayList<>();
        String[] namesArr = {"小明","二蛋","joshua317"};
        names.addAll(Arrays.asList(namesArr));
        System.out.println(names);
        //获取迭代器
        Iterator<String> iterator = names.iterator();
        //遍历集合元素,让迭代器 it 逐个返回集合中所有元素最简单的方法是使用 while 循环
        while (iterator.hasNext()) {
            String name = iterator.next();
            //删除集合里面字符串为"joshua317"的元素
            if (name.equals("joshua317")) {
                iterator.remove();
            }
        }
    }
} 
 
3.扩展-迭代器的原理
所有迭代器都最终实现接口Iterator,Iterator接口中包含三个基本方法,next(), hasNext(), remove(),其中对于List的遍历删除只能用Iterator的remove方法;JDK1.8中Iterator接口的源码如下:
package java.util;
import java.util.function.Consumer;
public interface Iterator<E> {
    boolean hasNext();
    E next();
    
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}接下来,我们基于ArrayList的Iterator的实现分析terator的原理(基于JDK1.8)
在ArrayList类中有个方法iterator(),此方法将返回一个iterator的实现,这里可以看出实现类叫Itr,通过其它源码可知,此类是AarryList的内部类,即ArryList的Iterator实现在ArrayList内部;
public Iterator<E> iterator() {
        return new Itr();
    }然后看下ArrayList中实现类Itr类的源码
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;
        Itr() {}
        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();
            }
        }
        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }从上面代码中可以看出,对于Iterator的实现中主要有几个变量cursor,lastRest, expectedModCount三个变量,其中cursor将记录下一个位置,lastRet记录当前位置,expectedModCount记录没有修改的List的版本号。
问题抛出:List中在iterator遍历的时候,为什么不能随便添加和删除元素吗?
在iterator遍历的时候抛出异常都是checkForComodification作的,根本原因是modCout和expectedModCount不相等,导致抛出异常。
我们来看下ArrayList的add和remove方法
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }从代码中可以看出只要对ArrayList作了添加或删除操作都会增加modCount版本号,这样在迭代期间,会不断检查modCount和迭代器持有的expectedModCount两者是否相等,如果不相等就抛出异常了。
关于modCount,API解释如下:
The number of times this list has been structurally modified. Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.
也就是说,modCount记录修改此列表的次数:包括改变列表的结构,改变列表的大小,打乱列表的顺序等使正在进行迭代产生错误的结果。
注意:仅仅设置元素的值并不是结构的修改
我们知道的是ArrayList是线程不安全的,如果在使用迭代器的过程中有其他的线程修改了List就会抛出ConcurrentModificationExceptionpackage com.joshua317;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
public class Main {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> names = new ArrayList<>();
        String[] namesArr = {"小明","二蛋","joshua317"};
        names.addAll(Arrays.asList(namesArr));
        //获取迭代器
        Iterator<String> iterator = names.iterator();
        //遍历集合元素,让迭代器 it 逐个返回集合中所有元素最简单的方法是使用 while 循环
        while (iterator.hasNext()) {
            String name = iterator.next();
            names.add("小红");
        }
    }
}Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
  at java.util.ArrayList$Itr.next(ArrayList.java:861)
  at com.joshua317.Main.main(Main.java:19) 
 
虽然在迭代器迭代期间不能对ArrayList作任何增删操作,但是可以通过iterator的remove作删除操作,从之前的代码可以看出,在iterator的remove()中有一行代码,expectedModCount = modCount; 这个赋值操作保证了iterator的remove是可用性的。
当然,iterator期间不能增删的根本原因是ArrayList遍历会不准,就像遍历数组的时候改变了数组的长度一样。










