Java list集合通过遍历删除元素异常分析
来源:互联网 发布:手机版vb编辑器 编辑:程序博客网 时间:2024/06/01 07:36
今天在分析ArrayList源码的过程中,突然想起许久以前发生的一个问题,就是在循环中删除元素的时候底层会报出一个异常“ConcurrentModificationException”,然后从网上也看了些资料,感觉例子都不是很全,所以结合网上前辈们的分析,自己也进行了一些补充,请大家进行参考的同时,自己也好做个记录。
首先看例子:
import java.awt.List;import java.util.ArrayList;import java.util.Iterator;import java.util.UUID;public class TestListRemove {public static void main(String[] args) {ArrayList<String> list = new ArrayList<String>(); list.add("苹果"); list.add("苹果"); list.add("橘子"); list.add("香蕉"); list.add("梨");remove1(list);//remove2(list);//remove3(list);//remove4(list); for (String s : list) { System.out.println("element : " + s); }}/** * 方法1:普通for循环 * */public static void remove1(ArrayList<String> list) { for (int i = 0; i < list.size(); i++) { String s = list.get(i); if (s.equals("苹果")) { list.remove(s); } } }/** * 方法2:高级for循环 * */public static void remove2(ArrayList<String> list) { for (String s : list) { if (s.equals("苹果")) { list.remove(s); } } }/** * 方法3:使用迭代器进行遍历,但是使用的是list集合中的删除方法 * */public static void remove3(ArrayList<String> list) {Iterator<String> it = list.iterator();while (it.hasNext()) {String x = it.next();if (x.equals("苹果")) {list.remove(x);}}}/** * 方法4:使用迭代器遍历和删除 * */public static void remove4(ArrayList<String> list) {Iterator<String> it = list.iterator();while (it.hasNext()) {String x = it.next();if (x.equals("苹果")) {it.remove();}}}}
结果分析:
方法1输出结果:
element : 苹果
element : 橘子
element : 香蕉
element : 梨
分析:还有一个元素包含“苹果”,未删除;以下是集合的部分源码:
@Override
public boolean remove(Object object) {
Object[] a = array;
int s = size;
if (object != null) {
for (int i = 0; i < s; i++) {
if (object.equals(a[i])) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++;
return true;
}
}
} else {
for (int i = 0; i < s; i++) {
if (a[i] == null) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++;
return true;
}
}
}
return false;
}
可以看到在删除第一个元素过程中,会执行System.arraycopy方法,导致当前元素删除时涉及到数组其它元素的移动。也就是,在遍历第一个元素“苹果”时因为符合删除条件,所以将该元素从数组中删除,并且将后一个元素移动(也就是第二个元素“苹果”)至当前位置,导致下一次循环遍历时后一个元素“苹果”并没有遍历到,所以无法删除。针对这种情况可以倒序删除的方式来避免;
---------------------------------------------
方法2输出结果:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:907)
at java.util.ArrayList$Itr.next(ArrayList.java:857)
at TestListRemove.remove2(TestListRemove.java:61)
at TestListRemove.main(TestListRemove.java:31)
分析:针对方法2出现的错误,从源码中看到了以下这段代码:
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
大家看到了吧,异常就是从这里报出的。
其实高级for循环底层也是通过迭代器Iterator实现的,本人也用反编译class文件也证实了这点,所以也会调用到迭代器的next方法;
其中在做集合的修改次数检查时,因为上面方法中list集合的remove(Object)方法修改了modCount的值,所以才会报出并发修改异常。要避免这种情况的出现,则在使用迭代器迭代时(显示或for-each的隐式)不要使用ArrayList的remove方法,改为用Iterator的remove方法即可。
---------------------------------------------
方法3输出结果:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:907)
at java.util.ArrayList$Itr.next(ArrayList.java:857)
at TestListRemove.remove2(TestListRemove.java:61)
分析:可以看到方法3与方法2出现的错误是一样的,也就证实了方法2的结论是对的;
------------------------------------------------------
方法4输出结果:
element : 橘子
element : 香蕉
element : 梨
分析:可以看到结果就是咱们想要的,注意哦,方法4里面用的是迭代器进行遍历的,同时remove方法也是自身的哦;
总结:
经对上面各方法中出现的异常进行分析,也给出了解决异常的方法。其实实现正确的结果方法挺多,相信了解了问题发生的原因,大家在使用中也会有更多的选择吧!
- Java list集合通过遍历删除元素异常分析
- JAVA遍历List集合并删除其中的元素
- Java遍历List集合并删除其中的元素
- Java 集合List删除元素
- Java动态 遍历List 时删除List特征元素 异常问题 及解决方式总结
- 【Java】Java遍历删除集合中的元素
- java遍历集合删除特定元素的 java.util.ConcurrentModificationException异常
- JAVA List 一边遍历一边删除元素,报java.util.ConcurrentModificationException异常
- java 遍历 删除元素 List Set
- Java List遍历中删除元素
- java 遍历 删除元素 List Set
- java中List遍历删除元素
- Java遍历List,删除自身元素
- 编程技巧系列(2)Java 集合(List,Set,Map)遍历时有条件删除特定元素
- 【Java】集合(List、Set、Map)遍历、删除、比较元素时的小陷阱
- Java 集合(List、Set)遍历、判断、删除元素时的小陷阱
- java中循环遍历删除List和Set集合中元素的方法
- Java集合之List遍历找到匹配元素删除方法总结
- PL/SQL连接服务端数据库
- 深入理解java线程池—ThreadPoolExecutor
- Failed to load resource: the server responded with a status of 500 ()
- Fragment 生命周期的详情
- 简单的快速排序
- Java list集合通过遍历删除元素异常分析
- Linux系统下activeMQ的安装
- 对称加密
- 云坤:“互联网+政务服务”整体建设方案
- EXPLAIN 的理解
- HDFS的读写限流方案
- 分析句子结构文法
- js获取iframe的值
- IntentFilter简述