在使用Iterator處理Collection時(shí),注意java.util.ConcurrentModificationException。
1.如果你僅僅是對(duì)collection進(jìn)行遍歷查詢(xún),那么不必?fù)?dān)心什么。
2.但如果你在遍歷過(guò)程中要對(duì)collection進(jìn)行刪除,那么你就要注意了。
For example:
private void testDel() {
- List<String> list = new ArrayList<String>();
- for (int i = 0; i < 10; i++) {
- String str = "td" + i;
- list.add(str);
- }
-
- for (Iterator it = list.iterator(); it.hasNext();) {
- String str = (String) it.next();
- if (str.equals("td5")) {
- // list.remove(str); // 刪除方法一
- it.remove(); // 刪除方法二
- }
- }
- }
上面的代碼運(yùn)行沒(méi)有問(wèn)題,但如果你用“方法一”替代“方法二”,則會(huì)出現(xiàn)java.util.ConcurrentModificationException。
(用for-each遍歷也會(huì)出個(gè)類(lèi)似問(wèn)題)
具體原因是可以看一下
先看看List中的remove方法源碼:
- public boolean remove(Object o) {
- if (o == null) {
- for (int index = 0; index < size; index++)
- if (elementData[index] == null) {
- fastRemove(index);
- return true;
- }
- } else {
- for (int index = 0; index < size; index++)
- if (o.equals(elementData[index])) {
- fastRemove(index);
- return true;
- }
- }
- return false;
- }
-
- private void fastRemove(int index) {
- modCount++; // 特別注意這里,這里只增加了modCount的值
- int numMoved = size - index - 1;
- if (numMoved > 0)
- System.arraycopy(elementData, index + 1, elementData, index,
- numMoved);
- elementData[--size] = null; // Let gc do its work
- }
接著看。刪除后得到下一個(gè)元素的代碼,it.next(): it為AbstractList的內(nèi)部類(lèi)Iterator的一個(gè)實(shí)例。
- public E next() {
- checkForComodification();
- try {
- E next = get(cursor);
- lastRet = cursor++;
- return next;
- } catch (IndexOutOfBoundsException e) {
- checkForComodification();
- throw new NoSuchElementException();
- }
- }
-
- final void checkForComodification() { //注意這個(gè)方法
- if (modCount != expectedModCount) //檢查這兩個(gè)值是否相同
- throw new ConcurrentModificationException();
- }
最后看Iterator的remove()方法的源代碼:
- public void remove() {
- if (lastRet == -1)
- throw new IllegalStateException();
- checkForComodification();
- try {
- AbstractList.this.remove(lastRet);
- if (lastRet < cursor)
- cursor--;
- lastRet = -1;
- expectedModCount = modCount; // 設(shè)置expectedModCount
- } catch (IndexOutOfBoundsException e) {
- throw new ConcurrentModificationException();
- }
- }
-
- final void checkForComodification() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- }
這下就明白了,list的remove方法只修改了modCount值,而iterator的remove能同步modCount和expectedModCount.