Inteator
是顶层的迭代器接口,定义了迭代器共同的方法。hasNext()
判断集合是否含有下一个元素,next(
)获取下一个元素。每个具体的集合类中都有一个迭代器内部类实现于Inteator
接口,用来历遍集合。
为了方便获取迭代器对象,
java
还提供了Iterable
接口,使用iterator()
方法来获取集合的迭代器。Collection
继承于Iterable
接口,而所有具体的集合类都实现了Collection
。因此在我们使用集合时只需要调用集合对象的iterator()
方法便可以得到迭代器对象。
/**
迭代器顶层接口
**/
public interface Inteator {
public abstract boolean hasNext();
public abstract Object next();
}
/**
获取迭代器对象的顶层接口
**/
public interface Iterable {
Iterator iterator();
}
/**
Collection接口 继承Iterable
**/
public interface Collection extends Iterable {
Iterator iterator();
}
public interface List extends Collection {
Iterator iterator();
}
public calss ArrayList implements List {
public Iterator iterator() {
return new Itr();
}
private class Itr implements Iterator { //接口的具体实现类
//包含了 所需功能 next() hasNext() 等
}
}
既然我们大概明白了迭代器的一个整体结构,我们来使用试一下:
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
//获取迭代器
Iterator iterator = list.iterator();
//历遍集合
while (iterator.hasNext()) {
Log.e("iterator",iterator.next().toString());
}
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 1
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 2
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 3
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 4
实验成功,可以迭代我们集合的所有元素,那么我们试试在迭代过程中修改集合会怎么样?
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
//获取迭代器
Iterator iterator = list.iterator();
//历遍集合
while (iterator.hasNext()) {
Log.e("iterator",iterator.next().toString());
//移除第一个元素
list.remove(0);
}
控制台报出了异常:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.serializationapplication/com.example.Main3Activity}: java.util.ConcurrentModificationException
解析ArrayList的迭代器源码:
private class Itr implements Iterator<E> {
int cursor; // 记录元素下标的指针
int lastRet = -1; // 记录当前元素下标位置的指针
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();
//指针+1,指向下一个元素
cursor = i + 1;
//返回当前元素,修改lastRet 指向当前的元素
return (E) elementData[lastRet = i];
}
public void remove() {
//当lastRet小于0则集合为null
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();
}
}
可以看出在
Itr
是ArrayList
的一个内部类,迭代器操作通过这个内部类,Itr
有个expectedModCount
属性,这个属性判断是否与modCount
相等,如果不相等抛出异常,modCount
则是记录list结构上发生变化的次数,可以看出在迭代时候checkForComodification()
方法检测两个的值不相等就抛出异常。则出现这个异常的时候一般都是在迭代过程中改变了集合,导致modCount
和expectedModCount
属性不相等。迭代器则提供了remove()
方法来移除元素,在删除元素后同时更新modCount
和expectedModCount
属性,因此不会报异常。