文章目录
🚩Java 迭代器详解
📚迭代器的定义
📒认识Iterator
✏️类结构图
✒️Iterable接口
🖍️Iterator接口
📃Iterator接口的方法
📙迭代器的使用
🏷️使用迭代器遍历集合
🔖Itertor的执行原理
⏳图示执行过程
⌛执行过程详解
🃏生成迭代器的快捷键
📕迭代器中的remove()
⛄迭代器的remove()方法使用
☃️迭代器遍历中调用集合revome()方法触发异常
📗增强for循环
📫认识增强for循环
📪基本语法
📬增强for循环的使用
📭增强for循环的快捷键
🚩Java 迭代器详解
 📚迭代器的定义
 迭代器是属于设计模式之一,迭代器模式提供了一种方法来顺序访问一个聚合对象中各个元素,而不保留该对象的内部表示。
1)Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
3)Iterator仅用于遍历集合,Iterator本身并不存放对象。
📒认识Iterator
 ✏️类结构图

 通过观察类结构图的继承关系我们发现,集合的顶层接口Collection继承Iterable接口。
✒️Iterable接口
public interface Iterable<T> {/*** Returns an iterator over elements of type {@code T}.** @return an Iterator.*/Iterator<T> iterator();
}
在Iterable接口中有一个Iterator方法,它返回一个Itertator对象。
🖍️Iterator接口
public interface Iterator<E> {boolean hasNext();E next();default void remove() {throw new UnsupportedOperationException("remove");}
}
📃Iterator接口的方法
| 返回值类型 | 方法名 | 功能 | 
|---|---|---|
| boolean | hasNext() | 判断集合是否还有元素,如果返回 true 表示集合还有元素,返回 false 表示集合中没有元素;一般对集合的访问通过 while(hasNext()) 判断是否还需要遍历。 | 
| E | next() | 获取集合中遍历的当前元素 ;一般先调用 hasNext() 方法判断是否存在元素,再调用 next() 获取元素,需要进行循环交替遍历集合中的元素。 | 
| void | remove | 删除集合中的元素。 | 
📙迭代器的使用
🏷️使用迭代器遍历集合
我们用ArrayList集合存放一些整型数据做示例,然后将其集合中的元素一一遍历打印输出。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class TestDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(111);list.add(222);list.add(333);Iterator<Integer> iterator = list.iterator();while(iterator.hasNext()) {int value = iterator.next();System.out.print(value + " ");}}
}
运行结果:

观察运行结果我们发现,通过迭代器我们将ArrayList集合中的元素一一打印了出来。
🔖Itertor的执行原理
在上述的示例中,迭代器是如何实现对集合的遍历呢?
⏳图示执行过程

 ⌛执行过程详解
 ①首先得到一个集合的迭代器Iterator iterator = list.iterator();
 ②进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置的元素111返回。
 ③再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置222的元素返回。
 ④再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置333的元素返回。
 ⑤再次进入while循环,调用hasNext()判断是否有下一个元素,返回false,循环结束。
在 迭代器的遍历过程中先通过hastNext()方法判断是否有下一个元素,如果存在下一个元素再调用next()方法获取元素,在这里next()方法先往后移动一个元素位置,再返回该位置的元素。因此,在调用next()方法之前必须要调用hastNext()方法进行检测;如果没有调用并且没有下一个元素,直接调用next()方法会抛出 NoSuchElementException异常。
🃏生成迭代器的快捷键
 一开始使用迭代器可能会觉得麻烦,但是如果用的Idea编译器是有快捷键的,输入itit再回车就会直接生成。

📕迭代器中的remove()
⛄迭代器的remove()方法使用
在Iterator接口中除了hasNext()和next()方法外,还有一个remove()方法,即删除集合中的元素。
如删除上述示例集合中的元素111
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"all"})
public class TestDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(111);list.add(222);list.add(333);System.out.println("删除前:" + list);Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()) {Integer value =  iterator.next();if(value == 111) iterator.remove();}System.out.println("删除后" + list);}
}
运行结果:

☃️迭代器遍历中调用集合revome()方法触发异常
 在Java集合中,以集合ArrayList为例,在使用中可能会遇到删除的需求场景,此时如果代码书写不当,极有可能会抛出java.util.ConcurrentModificationException异常信息。
 在上述示例中用Iterator调用了迭代器remove()方法,如果在使用中不小心调用了集合中的remove()方法会发生什么?
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"all"})
public class TestDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(111);list.add(222);list.add(333);System.out.println("删除前:" + list);Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()) {Integer value =  iterator.next();if(value == 111) list.remove(Integer.valueOf(111));}System.out.println("删除后" + list);}
}运行结果:

运行结果中抛出java.util.ConcurrentModificationException异常信息。这是因为触发了集合中并发修改的异常 接下来我们通过源码对抛出异常的原因进行剖析。
    public Iterator<E> iterator() {return new Itr();}
 在ArrayList集合的Iterator方法中,是通过返回Itr对象来获得迭代器的。Itr是ArrayList的一个内部类,它实现了Iterator接口,代码如下:
   private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint 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();}}
Itr类属性
| 属性 | 含义 | 
|---|---|
| cursor | 索引下标,表示下一个可以访问的元素的索引,默认值为 0 | 
| lastRet | 索引下标,表示上一个元素的索引,默认值为 -1 | 
| expectedModCount | 对集合修改的版本号,初始值为ModCount | 
ModCount定义在AbstractList接口中,初始值为0,定义如下:
 protected transient int modCount = 0;
ModCount是版本号,在对集合进行变更操作(增加、删除、修改等)的时候会对版本号进行 +1 操作。
结合上述代码进行抛出java.util.ConcurrentModificationException异常的解释。
 ①初始化ArrayList,添加三次元素,即三次调用add()方法,进行三次modCount++; 此时,m o d C o u n t = 3 , s i z e = 3 ; \color{red}{modCount = 3,size = 3;}modCount=3,size=3;
 ②初始化Iterator迭代器进行循环,此时,e x p e c t e d M o d C o u n t = m o d C o u n t = 3 , \color{red}{expectedModCount = modCount=3,}expectedModCount=modCount=3, c u r s o r = 0 , l a s t R e t = − 1 \color{red}{cursor=0,lastRet = -1}cursor=0,lastRet=−1
 ③进行hasNext判断,cursor != size;成立,进入循环
 ④调用next()方法,首先进行checkForComodification()校验,m o d C o u n t = = e x p e c t e d M o d C o u n t \color{red}{modCount == expectedModCount}modCount==expectedModCount,校验通过,返回值,此时l a s t R e t = 0 ; c u r s o r = 1 \color{red}{lastRet = 0;cursor = 1}lastRet=0;cursor=1
  
 final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
⑤调用集合remove()方法,modCount++;,此时m o d C o u n t = 4 ; s i z e = 2 \color{red}{modCount = 4;size = 2}modCount=4;size=2
 ⑥再次调用hasNext()方法判断,cursor != size;成立,进入循环
 ⑦调用next()方法进行校验,m o d C o u n t ! = e x p e c t e d M o d C o u n t \color{red}{modCount != expectedModCount}modCount!=expectedModCount,校验未通过,抛出java.util.ConcurrentModificationException异常
总结:
①在使用迭代器的remove()操作时,会将更新后的modCount给expectedModCount,两者会得到同步,但是在调用集合的remove()方法后,两个不会进行同步,进而导致在checkForComodification()校验时不通过,抛出java.util.ConcurrentModificationException异常。
②所以,在单线程下使用迭代器是没有问题的,但是在多线程下同时操作集合就不允许了,可以通过fail-fast快速失败机制,快速判断是否存在同时操作问题。因此,集合在多线程下使用是不安全的。
📗增强for循环
📫认识增强for循环
增强for循环可以代替Iterator迭代器,可以把它看做简化版的Iterator,和迭代器本质一样,其实它的底层实现就是Iterator迭代器,只能用于遍历集合或数组。
📪基本语法

📬增强for循环的使用
import java.util.ArrayList;
import java.util.List;public class TestDemo03 {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(111);list.add(222);list.add(333);System.out.println("====增强for循环遍历集合====");for(Integer i : list) {System.out.print(i + " ");}System.out.println();System.out.println("====增强for循环遍历数组====");int[] arr = {1,2,3,4,5,6};for (int i : arr) {System.out.print(i + " ");}}
}运行结果:

📭增强for循环的快捷键
与迭代器一样,增强for循环也有快捷键,输入I回车即可快速生成。

 原文链接:https://blog.csdn.net/sheng0113/article/details/122712947