java.util.ConcurrentModificationException异常分析

public class Test {

	public static void main(String[] args) throws Exception{
		List<String> strs = new ArrayList<String>();
		strs.add("zhangsan");
		strs.add("lisi");
		strs.add("wangwu");
		strs.add("zhaoliu");
		strs.add("chenqi");
		Iterator<String> it = strs.iterator();
		while(it.hasNext()) {
			String str = it.next();
			if(str.equals("wangwu")) {
				strs.remove(str);
			}
		}	
	}	
}


这段代码运行出错:
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
 at java.util.AbstractList$Itr.next(Unknown Source)
 at com.xtayfjpk.Test.main(Test.java:18)即String str = it.next();这句代码出错

 

这是因为ArrayList从AbstracArrayList继承而来,而在AbstracArrayList中有一个modCount字段,该字段表示这个List被structurally modifie的次数,ArrayList中的add,addAll,remove,clear,removeRange方法都会使modCount加1,当使用iterator方法得到Iterator对象(迭代器),其实是返回了一个Iterator接口的实现类AbstractList$Itr,该类为AbstracArrayList的一内部类,AbstractList$Itr类中有一个expectedModCount字段,当调用AbstractList$Itr的next方法时会先检查modCount的值是否等于expectedModCount的值,当两者值不相等时就会抛出java.util.ConcurrentModificationException异常。
为什么会抛出该异常呢?从代码可以看到调用了5次add方法,这时modCount的值也就为5,当当使用iterator方法得到Iterator对象时把modCount的值赋给了expectedModCount,开始时expectedModCount与modCount是相等的,当迭代到第三个元素(index=2)zhangsan”时,因为if条件为true,于是又调用了remove方法,调用remove方法时modCount值又加1,此时modCount的值为6了,而expectedModCount的值并没有改变,当再次调用AbstractList$Itr的next方法时检测到modeCount与expectedModCount不相等了,于是抛出异常。
当又发现当把if语句写成if(str.equals("zhaoliu"))时又没有抛出该异常,这又是为什么呢?一开始觉得很奇怪,这不是一样的吗,只不过换了一个元素而已,但后来仔细看才明白过来。AbstractList$Itr中还有一个名为cursor的字段用来指向迭代时要操作的元素索引,初始值为0,每调用一次next方法该字段值加1,注意是先从集合中取出了元素再加1的。当判断"zhaoliu"时,注意是倒数第二个元素,这些cursor的值为4,移除掉元素"zhaoliu"时,List的size为4,当调用AbstractList$Itr的hasNext方法判断有无下一个元素时,判断的依据为cursor的值与size是否相等,不相等则还有下一个元素,现在大家发现了,此时两者值刚好相等,也就没有往下执行next方法了,也就没有抛出异常了,这就是为什么说移动倒数第二个元素时不会抛异常的异常的原因了。
结论:当对ArrayList进行迭代的过程中不允许对ArrayList中的元素进行添加移除操作。
如果大家有这种需求一是可以使用java.util.concurrent.CopyOnWriteArrayList替代,该类允许在迭代的过程中对其中的元素进行添加移除操作,并且是线程安全的。二是迭代时返回ListIterator对象,ListIterator类中提供了remove和set方法用来操作next方法或previous方法返回的元素。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值