我们先看HashMap的Iterator源码怎么写的。
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
首先在构造器中expectedModCount = modCount通过这句话,将modCount保存下来,modCount
变量的意思是每次修改操作都会加1。
然后再遍历获取下一个几点或者是进行remove操作的时候,都会有这么一句话
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
查看构造函数中初始化的expectedModCount值和modCount 是否相等,不相等则抛出异常,什么时候会不相等呢。
- 当多线程的时候,1线程正在遍历集合,2线程对集合做了移除或者添加操作,这时候会抛出异常。
- 单线程的时候也会出现不相等的情况,在遍历的过程中,向集合中插入元素和删除元素。当然通过iterator删除元素是安全的,我们可以看到在iterator的remove操作中对 expectedModCount = modCount进行了重新赋值。而直接通过集合的remove方法是不行的。
再看一下ArrayList中LIstIterator的实现
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i];
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
cursor的含义是当前元素的位置,增加、删除元素的操作都是根据当前的cursor来实现了,具有获取前一个元素,后一个元素,和添加元素的功能。
总结
Iterator和ListIterator最大的区别应当是ListIterator在遍历的时候可以添加元素,而Iterator不可以添加元素,使用Iterator遍历的时候要注意快速失败的问题。