先贴出测试代码:
public static void main(String[] args) {
List list=new ArrayList();
list.add("aa");
list.add("bb");
list.add("cc");
Iterator iterator =list.iterator();
while(iterator.hasNext()){
String aaString=iterator.next();
if(aaString.equals("aa")){
iterator.remove();
}
}
for (String string : list) {
System.out.println(string);
}
}
运行结果:
bb
cc
我们跟进list.iterator()源码,选择 ArrayList 实现类,发现源码中ArrayList 继承与AbstractList,发现ArrayList实现类中并没有iterator()方法,那么肯定是在父类中,跟进源码发现,iterator()源码如下:
public Iterator iterator() {
return new Itr();
}
发现new 了一个 Itr,跟进继续,发现Itr 实现了Iterator接口,部分源码如下:
private class Itr implements Iterator {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
} private class Itr implements Iterator {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
根据源码我们发现Itr()里定义了三个变量:
int cursor = 0;下一个将要返回的元素的索引;
int lastRet = -1;lastRet记录上一次游标所在位置,因此它总是比cursor少1,-1表示最近的一次操作没有返回元素。
int expectedModCount = modCount;
其中的modCount 是AbstractList包含的一个modCount变量,它的初始值是0,当集合每被修改一次时(调用add,remove等方法),modCount加1。因此,modCount如果不变,表示集合内容未被修改。
expectedModCount 初始赋值等于modCount的值,后续会校验两个变量是否相等,如果不等会抛出异常ConcurrentModificationException。
为什么直接使用list.remove()会抛异常,而使用iterator中的remove方法却不报错?关键点在这里:
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
分析源码,咱们发现,首先判断本次操作是否有返回元素,如果没有,就抛出异常,然后检查expectedModCount和modCount是否相等,如果不想等就会抛出异常。接下来调用List本身的remove方法,索引指定位lastRet,此时,浮标减少一位,lastRet为-1,表示上次没有返回数据,最后关键一步,同步修改的modCount变量值,这样就保证remove后不抛出异常。
个人研究笔记,不准之处,还请见谅!