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
屬性,因此不會報異常。