集合移除元素中的坑!

情况一、使用迭代器Iterator循环时,对集合增加、删除,抛出并发修改                 异常

代码:

public class LinkedListTest {

    // 并发修改异常
    public static void main(String[] args) {
        
         ArrayList<String> aList=new ArrayList<String>();
//向集合中添加元素         
         aList.add("a");
         aList.add("b");
         aList.add("c");
         aList.add("d");
         System.out.println("移除前:"+aList);
 //创建迭代器  
         Iterator<String> it=aList.iterator();
         while(it.hasNext())
         {
             if("b".equals(it.next()))
             {
                aList.remove("b");//移除指定元素           
             }
         }
         System.out.println("移除后:"+aList);
    }
}

控制台输出:

           

   移除前:[a, b, c, d]
              Exception in thread "main" java.util.ConcurrentModificationException //并发修改异常
              at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
              at java.util.ArrayList$Itr.next(ArrayList.java:851)
              at collection.LinkedHashSetTest.main(LinkedHashSetTest.java:52)

 分析:

(1)哪里抛出的异常?

     上述代码 ,迭代器对象it.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];
        }

 (2) 出现的原因:

鼠标放在 iterator()方法上,Ctrl+鼠标左键,看到源码

   参数说明:    

       cursor:表示下一个元素的索引位置

  lastRet:表示上一个元素的索引位置

  expectModCount:预期被修改的次数

       在集合内部维护一个字段modCount用于记录集合被修改的次数,每当集合内部结构发生变化(add,remove,set)时,modCount+1。

  在迭代器内部也维护一个字段expectedModCount,同样记录当前集合修改的次数,初始化为集合的modCount值。当我们在调用Iterator进行遍历操作时,如果有其他线程修改list会出现modCount!=expectedModCount的情况,就会报并发修改异常java.util.ConcurrentModificationException

解释:

        一开始的创建集合,每次往集合中添加元素,那么集合内部就会 modCount+1。同理迭代器内部的维护字段expectedModCount记录当前修改的次数。

         问题来了。代码执行了 aList.remove("b");之后 modCount+1,再次进入循环。调用迭代器的next()方法

next()源码:

   public E next() {
                    checkForComodification();//检查集合的modCount 与迭代器expectedModCount
                    int i = cursor;
                    if (i >= SubList.this.size)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i + 1;
                    return (E) elementData[offset + (lastRet = i)];
                }

checkForComodification()源码:

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

执行发现   modCount != expectedModCount   记录次数不一致,搞事情!

解决方案:

      使用   ListIterator<String> it = aList.listIterator();

public class LinkedListTest {

    // 并发修改异常
    public static void main(String[] args) {
        
         ArrayList<String> aList=new ArrayList<String>();
//向集合中添加元素         
         aList.add("a");
         aList.add("b");
         aList.add("c");
         aList.add("d");
         System.out.println("移除前:"+aList);
 //创建迭代器  
        // Iterator<String> it=aList.iterator();
         ListIterator<String> it = aList.listIterator();
         while(it.hasNext())
         {
             if("b".equals(it.next()))
             {
               //aList.remove("b");//移除指定元素  
               it.remove();
             }
         }
         System.out.println("移除后:"+aList);
    }
}

情况一到此结束。

情况二、增强for循环,不能删除、增加 可以set 、输出

代码:

		 ArrayList<String> aList=new ArrayList<String>();
//向集合中添加元素		 
		 aList.add("a");
         aList.add("b");
         aList.add("c");
         aList.add("d");
         System.out.println("移除前:"+aList);
         //增强for循环,不能删除、增加 可以set 、输出
         for (String string : aList) {
			if("b".equals(string))
//				aList.remove("b");//异常
//			    aList.add("f") ;//异常
				aList.set(1,"v");//正常
		}

猜你喜欢

转载自blog.csdn.net/qq_38214630/article/details/85003022