1、概述
在写项目的时候,需要使用ForEach遍历将里面的数据根据操作实时更新,然后系统报了一个异常 ConcurrentModificationException ,就是这个"调皮"的异常,让我的数据实时更新不了了。
jdk文档的解释:当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常。
通俗易懂地来说,就是使用 ForEach 遍历同时,进行删除,增加从而出现的异常。平常使用的ArrayList, HashMap都有可能抛出这种异常,粗心的话,很容易犯这种错误,导致线上事故!
2. 情景列举
ForEach 遍历就是 For(Object o : List) 这种遍历方式,众所周知,ForEach循环只是JAVA的一个语法糖,在字节码层面上,等同于迭代器循环遍历。在这种情形下,增加元素一定会抛出ConcurrentModificationException,
而删除元素在大多数情况下,会抛出ConcurrentModificationException(小知识,当且仅当删除小标为 size()-2,也就是倒数第二个元素的时候,不会抛出异常)。
这种情况下,会有异常抛出
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (Integer i : list) {
if(i == 1){
list.remove(i);
}
}
3. 如何避免该异常
(1) 通过集合的普通遍历方式(并非forEach方式,因为foreach本身也是一种迭代)
for(i=0;i<size();i++)
(2)通过迭代器进行迭代删除:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> listIterator = list.iterator();
while (listIterator.hasNext()){
Integer next = listIterator.next();
System.out.println(next);
if (next==1) {
listIterator.remove();
}
}
System.out.println(list);
//输出结果为:
1
2
3
[2, 3]
注意:修改操作也能这样进行修改,但是添加操作是不能从末尾开始添加的,只能从当前位置开始添加,并且要切换成列表迭代器,代码如下:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
ListIterator<Integer> listIterator = list.listIterator();
while (listIterator.hasNext()){
Integer next = listIterator.next();
if (next==1) {
listIterator.add(1111);
}
}
System.out.println(list);
//输出结果为: [1, 1111, 2, 3]