直接上代碼:
public class test { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for (int i = 0 ; i < 10 ; i++ ) { list.add(i); } Iterator<Integer> iterator = list.iterator(); int i = 0 ; while(iterator.hasNext()) { if (i == 3) { iterator.remove(); //報(bào)java.lang.IllegalStateException異常 } i ++; } System.out.println(list); }}
為什么會報(bào)異常呢,通過一些查資料或者基礎(chǔ)較好的讀者知道只需要使用調(diào)用迭代器iterator.next()方法即可返回當(dāng)前元素,所以只需要在remove()方法前面加上
iterator.next();
注意這里有人會使用int x = iterator.next();這樣來把當(dāng)前的索引賦值然后再進(jìn)行操作,其實(shí)這樣是沒必要的,我們來根據(jù)這個(gè)例子深入的了解一下iterator的源碼是如何實(shí)現(xiàn)的。
首先我們調(diào)用的是list.iterator()方法來獲取這個(gè)迭代器,當(dāng)然list類并沒有實(shí)現(xiàn)這個(gè)方法,我們最終是使用它的子類ArrayList來獲取迭代器:
/** * Returns an iterator over the elements in this list in proper sequence. * * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @return an iterator over the elements in this list in proper sequence */ public Iterator<E> iterator() { return new Itr(); } /** * An optimized version of AbstractList.Itr */ 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; Itr() {} 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(); } }
可以看到,iterator()方法返回了一個(gè)Itr對象,接著下面,Itr是一個(gè)內(nèi)部類,并且實(shí)現(xiàn)了Itertor接口。
回到我們最初的問題,為什么在迭代器中不用在不使用next()方法情況下進(jìn)行remove操作會出錯(cuò)?我們來看下remove()方法源碼,
在remove方法第一行,即可看到:
if (lastRet < 0) throw new IllegalStateException();
當(dāng)lastRet < 0的情況下,會拋出IllegalStateException異常,那么這個(gè)lastRet是什么呢,其實(shí)在Itr類就定義了這個(gè)lastRet變量,和它一起的還有cursor,expectedModCount;
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;
通過注釋可以看到,lastRet就是上個(gè)元素的索引,默認(rèn)是-1,所以直接調(diào)用迭代器的remove()方法會報(bào)錯(cuò)就是這個(gè)原因,
所以在上面的next()方法里,我們可以看到這樣的代碼:
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];
它會把cursor游標(biāo)賦值給i,然后進(jìn)行+1操作,最后將lastRet賦值成i,所以lastRet就不是默認(rèn)的-1了,而是會得到上個(gè)元素的索引,
所以綜合上述的結(jié)論,在使用迭代器iterator.remove()方法前,一定先調(diào)用next()方法來給變量lastRet進(jìn)行賦值操作。