作为一个平凡的码农,相信同道中人对集合这个词都不陌生,日常工作中我们经常会涉及到集合的各种操作,本篇文章抛砖引玉总结下ArrayList遍历时删除集合元素踩得坑,以及解决问题的集中方法,供大家参考!
一、事情起因
某天下午正犯困的时间点,领导在工作群里发了一张代码图,问大家这样的写法是否有问题,第一反应是不是自己的bug?
List<Map<String,Object>> list = new ArrayList<>();
Map<String,Object> m = new HashMap<String,Object>();
m.put("a1", 12);
Map<String,Object> m1 = new HashMap<String,Object>();
m1.put("a1", 11);
Map<String,Object> m2 = new HashMap<String,Object>();
m2.put("a1", 11);
list.add(m);
list.add(m1);
list.add(m2);
System.out.println("去重前:" + JSON.toJSON(list));
//去重
List<String> sids = new ArrayList<>();
for(Map<String,Object> map : list){
String ret = String.valueOf(map.get("a1"));
if(sids.contains(ret)){
list.remove(map);
}
sids.add(ret);
}
大家立马精神起来认真看了下这段代码,纷纷发表自己见解,但毕竟有理有据才更有说服力,于是开始亲测:
二、究其因果
代码中直接使用增强for循环,判断条件成立时删除元素,此方法在遍历时会抛出ConcurrentmodificationException异常,为了查清楚异常原因,查看源码remove方法中调用fastRemove(基于JDK1.8)
fastRemove方法中显示modCount在操作时会自增加1:
移除元素后遍历继续执行next():
checkForComodification()方法中比较两个参数是否相等,初始值是一样的,移除元素后modCount+1,会触发异常:
三、探索方案
我们日常用到遍历集合最多的方法有以下几种:
1、使用增强for循环,经测试报异常——不可用
代码:
结果:
2、使用普通for循环(正序),经测试去重结果不准确——不可用
代码:
结果:
3、使用迭代器自身的remove方法,经测试——可用
代码:
结果:
4、使用通for循环(倒序),经测试——可用
代码:
结果:
5、使用jdk1.8的Stream流操作,经测试——可用
代码:
结果:
6、使用java.util.concurrent下的CopyOnWriteArrayList替代ArrayList,经测试——可用
代码:
结果:
总结:经过测试验证,我们发现3、4、5、6几种方法是可以实现我们的去重目的的,测试过程中可能存在其他偶然因素造成结果不准确,欢迎大家验证并提出建议和见解!