解决ArrayList的ConcurrentModificationException

1 问题 :在list<String> 中清空所有的记录,只使用使用单循环,不使用removeAll()

 

2 可以写出五种方式,代码如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListRemoveTest {
	 public static void main(String[] args) {  
		         ListRemoveTest test = new ListRemoveTest();  
		           
		         System.out.println("-1-使用jdk5.0以后的增强for循环去remove");  
		         List<String> list = test.buildList();  
		         try {  
		             for (String str : list) {  
		                 list.remove(str);  
		             }  
		         } catch (Exception e) {  
		             // java.util.ConcurrentModificationException  
		             e.printStackTrace();   
		         }  
		   
		         System.out.println("-2-使用Iterator的remove");  
		         list = test.buildList();  
		         try {  
		             Iterator<String> iterator = list.iterator();  
		             while (iterator.hasNext()) {
		            	 iterator.next();
		                 iterator.remove();  
		             }  
		         } catch (Exception e) {  
		             // java.lang.IllegalStateException  
		             e.printStackTrace();  
		         }  
		   
		         System.out.println("-3-iterator遍历+list的remove");  
		         try {  
		             list = test.buildList();  
		             for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {  
		                 String str = (String) iterator.next();  
		                 list.remove(str);  
		             }  
		         } catch (Exception e) {  
		             // java.util.ConcurrentModificationException  
		             e.printStackTrace();  
		         }  
		           
		         System.out.println("-4-使用list的remove(int)方法. [由后向前删除]");  
		         list = test.buildList();  
		         for (int i = list.size(); i > 0; i--) {  
		             list.remove(i - 1);  
		         }  
		   
		         System.out.println("-5-使用list的remove(int)方法. [由前向后删除]");  
		         list = test.buildList();  
		         for (int i = 0; i < list.size(); i++) {  
		             list.remove(0);  
		         }  
		     }  
		   
		     private List<String> buildList() {  
		         List<String> list = new ArrayList<String>();  
		         list.add("a");  
		         list.add("b");  
		         list.add("c");  
		         return list;  
		     }  
}

 3运行结果如下:

-1-使用jdk5.0以后的增强for循环去remove
java.util.ConcurrentModificationException
-2-使用Iterator的remove
-3-iterator遍历+list的remove
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:781)
	at java.util.ArrayList$Itr.next(ArrayList.java:753)
	at com.jdk.ListRemoveTest.main(ListRemoveTest.java:14)
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:781)
	at java.util.ArrayList$Itr.next(ArrayList.java:753)
	at com.jdk.ListRemoveTest.main(ListRemoveTest.java:39)
-4-使用list的remove(int)方法. [由后向前删除]
-5-使用list的remove(int)方法. [由前向后删除]

2,4,5运行正常,1,3抛出

java.util.ConcurrentModificationException

 

4问题原因:

1,3都是因为list的长度改变,Iterator执行next()方法时,调用checkForComodification()时出错,1,3是同一个问题,这两个方法remove操作都是执行的是ArrayList中的remove方法,根本原因在于expectedModCount与modCount他们的不相等,由于执行了ArrayList中的remove(),modCount在每一次循环值会发生改变,而expectedModCount并没有发生,在执行checkForComodification()方法就会抛出异常。

2之所以正确运行是因为调用了Iterator的remove方法,4,5不会执行checkForComodification()操作,所以不会出现这种异常。

 

5结论 :在执行remove()不要将ArrayList 与Interator混合使用,单独使用Interator以及ArrayList的删除都是OK的

6参考的源码

Iterator的next()方法:

        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];
        }

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

 Iterator的remove()方法:

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                //当执行remove操作后,将改变的modCount值重新赋给expectedModCount
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

 ArrayList的remove()方法:

 

 

  /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
 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 remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        //此处modCount发生了改变,但expectedModCount仍然未发生变化,所以再执行下一次循环时执行
        //Interator的next()方法当然会报错
        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
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值