首先迭代器要实现迭代器的接口,Iterator接口中有4个方法:
1.hasNext()
2.next()
3.remove()
4.forEachRemaining(Consumer<? super E> action)
在ArrayList中,内部类Itr实现了Iterator的接口并且重写了这四个方法:
在itr中重新定义了三个参数,cursor(当前index),lastRet(上一个index,初始值-1),expectedModCount(修改次数,初始化的时候等于ArrayList的修改次数)
1.hasNext()
返回cursor != size(集合长度),如果相等则没有下一个值,循环结束
2.next()
获取下一个值,首先调用checkForComodification方法检查expectedModCount是否等于ArrayList中的modCount,不等于则抛出ConcurrentModificationException异常,定义i等于 cursor,如果i>ArrayList.size,抛出NoSuchElementException异常,定义elementData等于ArrayList.elementData,判断i是否大于等于elementData的长度,true则抛出ConcurrentModificationException异常,将cursor参数+1 并将lastRet参数赋值i ,返回elementData[lastRet]
3.remove()
删除方法,调用ArrayList的remove的方法(该方法的实现在后面的博客中详细的讲一下),删除lastRet索引的元素,并且将cursor赋值lastRet,lastRet赋值-1,expectedModCount赋值modCount(防止过不了checkForComodification方法的校验),在使用迭代器迭代ArrayList的时候 要注意remove方法的使用,该方法删除的是最后一个操作的元素,因为在next方法如果调用了,则删除的是你当前操作的元素,如果先调用的remove方法那么删除的元素为上一个你操作的元素。
4.forEachRemaining(Consumer<? super E> action)
函数式遍历接口,该方法和使用通过hasNext和newt方法遍历有一定的区别,该方法只有在方法的最后更新了一次cursor和lastRet。和next,hasNext方法共用了cursor和lastRet,如果遍历进行到一半,然后使用另一种遍历方式,那么遍历不会从头开始,而是从结束的地方开始
5.checkForComodification()
主要用于验证在循环遍历过程中,是否调用了ArrayList的add,remove等操作,这些操作会增加modCount的值,导致该值和Iterator中的exprctedModCount值不相等,破坏原来的结构,遍历出错。
以下为源码:
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;
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();
}
}