以ArrayList为例来看代码,其他集合类似原理
代码一
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();
array.add("11");
array.add("22");
array.add("33");
array.add("44");
for (String str : array) {
if("22".equals(str)){
array.remove(str);
}
}
}
代码一执行报错
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at com.abc.dto.TestIterator.main(TestIterator.java:23)
代码二,与一区别只是注释了一行
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();
array.add("11");
array.add("22");
array.add("33");
//array.add("44");
for (String str : array) {
if("22".equals(str)){
array.remove(str);
}
}
System.out.println("执行完毕");
}
代码二正常执行
执行完毕
Process finished with exit code 0
为啥子嘞,foreach循环就是iterator,打断点就能看到走了iterator的hasNext和next方法进行循环遍历,等同下边
Iterator<String> iterator = array.iterator();
while(iterator.hasNext()) {
String next = iterator.next();
}
来看ArrayList内部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
// 顾名思义 expectedModCount 就是期望目前的修改次数
// modCount当前arayList的变量,每次对list的增删改都会加一,一个版本号的东西
// 遍历过程中对这个变量进行判断来检测是否过程中被修改过list
int expectedModCount = modCount;
Itr() {}
// 这个每次循环之前会有这个方法来判断是否下一次循环
// 也就解释了为什么代码二没报错,因为删除后size为2,下一次遍历前cursor也为2,所以结束了循环,所以没报错
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];
}
// 如果list对象的版本号和遍历对象不同则表示遍历过程中被修改过了,报错
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如果想在遍历过程中删除元素,用下边的方式,iterator.remove()方法,内部调用list对象的remove操作,也会更新上边说的版本号
Iterator<String> iterator = array.iterator();
while(iterator.hasNext()) {
String next = iterator.next();
if("22".equals(next)){
iterator.remove();
}
}
增加元素的话就得使用下边这个遍历器了
ListIterator<String> stringListIterator = array.listIterator();