记录一下
1.首先看一下ArrayList类的继承关系图:
Java集合的根接口Collection,继承了Iterable接口。
Iterable接口包含一个能产生Iterator对象的方法,并且Iterable被foreach用来在序列中移动。因此如果创建了实现Iterable接口的类,都可以将它用于foreach中。使用foreach来遍历集合使得代码更加优雅。
2.Iterator接口中定义了三个方法:
利用迭代器Iterator遍历集合:
public class IteratorTest {
public static void main(String[] args) {
ArrayList<String> strings = new ArrayList<>();
strings.add("zhangsan1");
strings.add("zhangsan2");
strings.add("zhangsan3");
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next);
}
}
}
3.如果使用foreach遍历或者使用迭代器遍历的过程中,对集合结构进行修改(添加或者删除元素),会报错
public class IteratorTest {
public static void main(String[] args) {
ArrayList<String> strings = new ArrayList<>();
strings.add("zhangsan1");
strings.add("zhangsan2");
strings.add("zhangsan3");
// foreach遍历
for (String string : strings) {
if (string.equals("zhangsan3")){
strings.remove("zhangsan3");
}
}
// 迭代器遍历
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next.equals("zhangsan3")){
strings.remove(next);
}
}
System.out.println(strings);
}
}
原因分析:以ArrayList为例:
ArrayList中关于Iterator接口的实现:(JDK8在Line846行左右)
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
// modCount 此列表经过结构修改的次数
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
ArrayList的remove和add方法调用时,会有一个modCount++操作,记录list被改变的次数.获取集合的Iterator时: int expectedModCount = modCount;两者相等.在迭代的时候,执行add或remove时,modCount会++,而期望中expectedModCount没有改变,两者就不再相等.所以在next()方法里执行checkForComodification()方法就会抛出异常.
在迭代器遍历时,可以通过Iterator对象的remove方法来删除集合中的元素,因为该remove()方法中执行expectedModCount = modCount,同步了两者的值,所以不会再抛异常.