List的remove(对象)操作有时候会报ConcurrentModificationException异常

it2024-12-11  15

public class ListTest {      public static void main(String[] args) {         List<Integer> intList = new ArrayList<Integer>();         Collections.addAll(intList, 1, 2, 3, 5, 6);         for(Integer value : intList) {             // 符合条件,删除元素             if(value == 3 || value == 5) {                intList.remove(value);             }         }         System.out.println(intList);      }  }  

执行后,会抛出ConcurrentModificationException,字面意思是并发修改异常。异常跟踪信息如下:

 

Exception inthread "main" java.util.ConcurrentModificationException

         atjava.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)

         at java.util.AbstractList$Itr.next(AbstractList.java:420)

         at ListTest.main(ListTest.java:13)

       可以大概看出是执行到AbstractList中内部类Itr的checkForComodification方法抛出的异常,至于为什么出现异常,这里可以大概解释一下。集合遍历是使用Iterator, Iterator是工作在一个独立的线程中,并且拥有一个互斥锁。Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast原则 Iterator 会马上抛出java.util.ConcurrentModificationException 异常。所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。

       而要解决这个问题,可以使用Iterator的remove方法,该方法会删除当前迭代对象的同时,维护索引的一致性。如:

public class ListTest {      public static void main(String[] args) {         List<Integer> intList = new ArrayList<Integer>();         Collections.addAll(intList, 1, 2, 3, 5, 6);         Iterator<Integer> it = intList.iterator();         while(it.hasNext()) {             Integer value = it.next();             if(value == 3 || value == 5) {                it.remove();             }         }         System.out.println(intList);      }  }  

  输出正确结果:[1, 2, 6]。

 

   不使用迭代器的解决方案就是,自己维护索引,删除一个元素后,索引-1,如:

public class ListTest {      public static void main(String[] args) {         List<Integer> intList = new ArrayList<Integer>();         Collections.addAll(intList, 1, 2, 3, 5, 6);         for(int i = 0; i < intList.size(); i++) {             Integer value = intList.get(i);             if(value == 3 || value == 5) {                intList.remove(i);                i--;             }         }          System.out.println(intList);      }  }  

输出正确结果:[1, 2, 6]。

 

 

       还有种取巧的方式是从最后一个元素开始遍历,符合条件的删除,如:

public class ListTest {      public static void main(String[] args) {         List<Integer> intList = new ArrayList<Integer>();         Collections.addAll(intList, 1, 2, 3, 5, 6);         for(int i = intList.size() - 1; i >= 0; i--) {             Integer value = intList.get(i);             if(value == 3 || value == 5) {                intList.remove(i);             }         }          System.out.println(intList);      }  }  

输出正确结果:[1, 2, 6]。

 

       最后,Java集合类框架真是大大方便了开发,不用自己去维护数组,随时担心着越界等问题。当然List的实现类对插入、删除的效率不太一样,这取决于其实现的数据结构,是选择删除,还是选择新建个集合,这里就不做讨论了。

转载于:https://www.cnblogs.com/snowalwaysboy/p/7850425.html

相关资源:数据结构—成绩单生成器
最新回复(0)