foreach循環遍歷List,刪除其中某元素報錯問題

1. foreach循環遍歷List集合,並刪除其中的"lisi"

public class TestListDel {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("zhangsan");
		list.add("simon");
		list.add("lisi");
		list.add("smith");
		list.add("lucy");
		
		for (String string : list) {
			if(string.equals("lisi")) {
				list.remove(string);
			}
		}
		
		//list.stream().forEach(name -> System.out.println(name));
		System.out.println(list);

	}

}

報錯(java.util.ConcurrentModificationException)如下:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at abc.TestListDel.main(TestListDel.java:32)

2. 錯誤分析

通過查看源碼,發現foreach循環執行時候,底層執行的是Iterator。其代碼如下:

/**
     * 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();
            }
        }

        @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();
        }
    }

當走到 next()方法時候,會執行校驗 checkForComodification(),由於modCountexpectedModCount不相等,所以報錯了。

而之所以不相等,是由於在執行list.remove(string);時候,modCount的值被修改了。
在這裏插入圖片描述

3. 總結

foreach循環遍歷刪除的代碼:

for (String string : list) {
	if(string.equals("lisi")) {
		list.remove(string);
	}
}

等價於如下代碼:

Iterator<String> it = list.iterator();
while(it.hasNext()){
	if(it.next().equals("simon")) {
		list.remove(it.next());
	}
}

4. 正確的寫法,使用迭代器Iterator

public class TestListDel {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("zhangsan");
		list.add("simon");
		list.add("lisi");
		list.add("smith");
		list.add("lucy");
		
		Iterator<String> it = list.iterator();
		while(it.hasNext()){
			if(it.next().equals("simon")) {
				it.remove();
			}
		}
		System.out.println(list);

	}

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章