注意了!ArrayList 增刪千萬不要亂用…


注意了!ArrayList 增刪千萬不要亂用…


編程過程中常常需要使用到集合,而ArrayList是我們常常使用的,但是最近在一次刪除和增加中出現了一些問題,分享記錄下。

分下如下倆段代碼

<code>List<string> arrayList1 = new ArrayList<string>();
arrayList1.add("1");
arrayList1.add("2");
for (String s : arrayList1) {
    if("1".equals(s)){
         arrayList1.remove(s);
    }}
    List<string> arrayList2 = new ArrayList<string>();
    arrayList2.add("2");arrayList2.add("1");
    for (String s : arrayList2) {
        if("1".equals(s)){
        arrayList2.remove(s);
    }
}/<string>/<string>/<string>/<string>/<code>

程序運行結果如下:

arrayList1的remove方法成功執行, arrayList2的remove方法運行拋出ConcurrentModificationException異常。

我們查看源代碼來分析異常原因 因為foreach的本質就是使用迭代器Iterator,所有的Collecation集合類都會實現Iterable接口。 找到ArrayList類的iterator()方法

<code>public Iterator iterator() {
    return new Itr();
}
/<code>

迭代器的本質是先調用hasNext()方法判斷存不存在下一元素,然後再使用next()方法取下一元素

<code>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\\];
}/<code>

上面arraylist1為什麼能remove成功呢?其實它只循環了一次,所以成功了。

因為它在remove元素1之後,它的size-1變成1,然後Itr內部的cursor變量由0變成1,此時1=1,循環結束,所以成功了。

arraylist2為什麼remove失敗呢?因為它在循環第二次的時候,也remove成功了,但是第三次判斷next的時候cursor的值為2導致不等於現在的size 1,所以執行了next方法,最重要的來了,之前remove的操作導致ArrayList的modCount值加1,然後Itr類中的expectedModCount保持不變,所以會拋出異常。

<code>final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}/<code>

同理可得,由於add操作也會導致modCount自增,所以不允許在foreach中刪除, 增加,修改ArrayList中的元素。

對此,推薦大家使用迭代器Iterator刪除元素。

<code>Iterator<string> ite = arrayList2.iterator();
while(ite.hasNext()) {
    if("1".equals(ite.next())) {
        ite.remove();
    }
}/<string>/<code>

如果存在併發操作,還需要對Iterator進行加鎖操作。


分享到:


相關文章: