解决Java ArrayList的ConcurrentModificationException问题

  工作中应用ArrayList的场景很多,其中遍历ArrayList的过程中删除其中元素的情况相信也不少,而且相信很多人都会遇到ConcurrentModificationException异常。我们来研究一下为何会抛这个异常,并制定解决方法。

在jdk5之后有5种遍历并删除的写法:

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



运行结果:
-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


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

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

注意事项:
在使用Iterator的时候,必须先调用next()来获取第一个元素,否则调用remove()的时候会抛IllegalStateException错误。

猜你喜欢

转载自sptieren.iteye.com/blog/2314995