下圖是來自阿里巴巴java開發手冊,里面的例子有些特殊,在后面會有一般的例子,請往后看。
個人理解:在foreach循環里面進行元素的remove/add操作就是:在foreach循環里使用集合本身的remove/add方法, Iterator方式就是使用集合對應的iterator的remove/add方法,即下圖中的iterator.remove() //刪除當前遍歷的這個元素
foreach本質上是java中的語法糖,對數組操作時,底層原理和普通的for循環一樣;而對列表操作時,實際上是采用了迭代器的方法。
為什么不要使用集合本身的remove/add方法呢?
List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); for (String temp : list) { if("1".equals(temp)){ list.remove(temp); } }
反編譯結果如下:
List list = new ArrayList(); list.add("1"); list.add("2"); Iterator i$ = list.iterator(); // 語句1 do { if(!i$.hasNext()) break; String temp = (String)i$.next(); // 語句2
if("1".equals(temp)) list.remove(temp); // 語句3
} while(true);
ArrayList的iterator()方法如下:
重要參數:
modCount:是ArrayList修改的次數,在add()、remove()/removeAll()、clear()等方法中會修改modCount的值。
expectedModCount:在獲得ArrayList對象的Iterator的時候,把modCount的初值賦給expectedModCount
語句1: list.iterator() 返回的是一個Itr對象,
語句2: next()方法中,首先會執行checkForComodification()方法(源碼如下),如果 modCount != expectedModCount 就會拋出ConcurrentModificationException異常,在語句3中,執行了list.remove(temp),會修改modCout的值,那么在下一次執行next()方法的時候就會報錯!! 所以不要在foreach循環里面進行元素的remove/add操作
另:如果把上面代碼 if("1".equals(temp)) 改成 if("2".equals(temp)) 即直接刪除最后一個元素,會拋出ConcurrentModificationException異常,因為在刪除最后一個元素的過程中,首先cursor 等於 size, 然后執行 a.remove(temp) 【-》modCount發生改變】方法后,size=size-1, 再執行hashNext()方法,發現返回結果是false(cursor != size) 又會進行一次循環,在next()方法里面就拋出異常。 所以不要在foreach循環里面進行元素的remove/add操作
public Iterator<E> iterator() { return new 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; 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(); } }final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
為什么說上面的例子有些特殊,因為list集合中只有兩個數據,如果是只刪除第一個數據,執行list.remove(temp)后, cursor=size-1, size=size-1, 所以就會推出循環。沒有拋出異常。
將例子改為:
List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String temp : list) { if("1".equals(temp)){ list.remove(temp); } }
現在有了三個元素,除開直接刪除倒數第二個元素不會拋出異常(因為會出現 cursor=size-1, size=size-1的情況,然后退出循環),直接刪除其他元素都會拋出ConcurrentModificationException異常!!
如果是下面的寫法,更是會拋出異常!
List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String temp : list) { list.remove(temp); }
直接使用iterator的remove/add方法對集合做修改:
List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); Iterator iterator = list.iterator(); while(iterator.hasNext()) { String temp = (String) iterator.next(); iterator.remove(); }