簡(jiǎn)書 賈小強(qiáng)
轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處铝宵,謝謝首懈!
你將在面試中被問這個(gè)問題很多次,比如垂睬,在Java中迭代器(Iterator)如何工作的媳荒,怎么刪除List中的元素抗悍?什么時(shí)候拋出IllegalStateException
? 什么時(shí)候在會(huì)拋出ConcurrentModificationException
? Iterator和ListIterator之間的區(qū)別?
什么時(shí)候拋出IllegalStateException
Java迭代器接口定義如下
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
hasNext() 如果仍有元素可以迭代,則返回 true钳枕。
next() 返回迭代的下一個(gè)元素缴渊。
remove() 從迭代器指向的 collection 中移除迭代器返回的最后一個(gè)元素(可選操作)。每次調(diào)用 next 只能調(diào)用一次此方法鱼炒。否則拋出IllegalStateException
衔沼,如下
Iterator<Integer> iterator1=arrayList.iterator();
iterator1.next();
iterator1.remove();
iterator1.remove(); // throws IllegalStateException
正確的方式應(yīng)該是:
Iterator<Integer> iterator1=arrayList.iterator();
iterator1.next();
iterator1.remove();
iterator1.next();
iterator1.remove();
什么時(shí)候拋出ConcurrentModificationException
在Java中,當(dāng)你實(shí)例化一個(gè)迭代器昔瞧,當(dāng)你修改集合的時(shí)候指蚁,它就會(huì)計(jì)數(shù)。如果迭代器檢測(cè)到你用不是用它修改了集合(比如同一個(gè)集合的另一個(gè)迭代器)自晰,它不能保證操作的正確性凝化,比如一個(gè)一個(gè)迭代器指向另一個(gè)迭代器剛剛刪除的元素前面,現(xiàn)在這個(gè)迭代器就是無效的酬荞,而且不應(yīng)該再被使用搓劫,迭代器的設(shè)計(jì)使它能夠檢測(cè)到這種修改。如果發(fā)現(xiàn)那么拋出ConcurrentModificationException
混巧。
ArrayList<Integer> arrayList=new ArrayList<Integer>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
Iterator<Integer> iterator1=arrayList.iterator();
Iterator<Integer> iterator2=arrayList.iterator();
iterator1.next();
iterator1.remove();
iterator2.next(); // throws ConcurrentModificationException
由于iterator2檢測(cè)出了這個(gè)List被從外部修改了枪向,所以對(duì)iterator2.next的調(diào)用拋出ConcurrentModificationException
ArrayList的方法有一個(gè)計(jì)數(shù)器的modcount,聲明為:
protected transient int modCount = 0;
當(dāng)你用一個(gè)ArrayList創(chuàng)建一個(gè)Iterator/ListIterator咧党,這個(gè)modCount被用來初始化Iterator對(duì)象中的一個(gè)叫expectedModCount的字段
int expectedModCount = modCount;
在ArrayList上的任何操作(不使用迭代器實(shí)例)將增加modCount秘蛔。迭代器的所有方法執(zhí)行前都講檢查modCount == expectedModCount。如果它們不相等凿傅,則拋出異常缠犀。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Iterator和ListIterator之間的區(qū)別
先看如下類層次關(guān)系
可以發(fā)現(xiàn)實(shí)現(xiàn)Collection接口的所有集合都可以產(chǎn)生Iterator
而只有實(shí)現(xiàn)List接口的集合(比如ArrayList,LinkedList聪舒,Vector辨液,Stack)可以產(chǎn)生ListIterator
原因在于使用Iterator,比如計(jì)算集合元素的總是或者符合某種條件的元素個(gè)數(shù)這種和順序無關(guān)的并沒有問題箱残,但因?yàn)榈鳎↖terator和ListIterator)描述了元素的位置關(guān)系滔迈,而add方法又依賴于這種位置關(guān)系,那么比如對(duì)于Set這種完全無序的集合Iterator提供add方法就不合適了(Set集合本身是根據(jù)元素的hashCode來決定元素的位置被辑,而如果直接用迭代器add燎悍,將一個(gè)元素直接添加到上一個(gè)元素的后面,那將破壞哈希機(jī)制)盼理,于是分出了ListIterator谈山,專門針對(duì)有序集合提供add方法
我希望以上的解釋能幫助你回答這個(gè)面試問題。
Happy Learning !!