java.util.ConcurrentModificationException
来源:互联网 发布:我的世界mac版整合包 编辑:程序博客网 时间:2024/06/05 18:43
最近在项目过程中,遇到一个需要在set集合中删除满足条件元素的需求,当时没有多想,直接实用Iterator遍历Set,然后,调用了Set的remove(Object o)方法将对象删除,结果,意外的报了一个异常:java.util.ConcurrentModificationException。经过分析,引起该异常的原因正是因为执行了Set的remove(Object o)方法。下面贴出一段测试代码:
public class Test { public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("one"); set.add("two"); set.add("three"); Iterator<String> it = set.iterator(); String str = null; while (it.hasNext()) { str = it.next(); set.remove(str); } System.out.println(set); }}
执行结果:
Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)at java.util.HashMap$KeyIterator.next(HashMap.java:828)at com.action.ajax.Test.main(Test.java:16)
查看JDK源码发现在迭代Iterator时建立了一个List的内部类Itr。
源码:
public Iterator<E> iterator() { return new Itr(); }
在new Itr()时有一个关键性的操作
int expectedModCount = modCount;
我们先看一下当List调用remove方法执行的代码:
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false;}private void fastRemove(int index) { modCount++; int numMoved = size – index – 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null;}
看到这里大家注意一下modCount这个变量,当执行remove方法时此变量执行了modCount++操作。
再看一下 iterator.next()操作
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();}
看到这儿相信大家已经应该明白了为什么会出现在这个异常了。当迭代器Iterator创建时,将定义一个变量expectedModCount,并且把modCount的值赋给它;在List执行remove()时,modCount++;在Iterator执行next()迭代下一个元素时,做了一个if判断比较expectedModCount和modCount值时候相同,如果不同直接抛出ConcurrentModificationException异常:
在这里提供给大家两种解决方案:
方案一:在集合remove之前,迭代器也remove:
public class Test { public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("one"); set.add("two"); set.add("three"); Iterator<String> it = set.iterator(); String str = null; while (it.hasNext()) { str = it.next(); it.remove(); set.remove(str); } System.out.println(set); } }
方案二:新建一个list,把需要迭代删除的元素保存进list在set遍历完成后调用removeAll(Object o)删除即可:
public class Test { public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("one"); set.add("two"); set.add("three"); Iterator<String> it = set.iterator(); String str = null; List<String> list = new ArrayList<String>(); while (it.hasNext()) { str = it.next(); list.add(str); } set.removeAll(list); System.out.println(set); }}
此外,其他如List等集合使用Iterator迭代删除时也会出现这样的异常,大家采用类似的解决方法即可。 因为时间问题,对本异常没有进行过深的分析,暂时也只想到这两种解决方案,不足之处希望大家补充,后续会抽时间深入研究并完善此文。
- 【ConcurrentModificationException】java.util.ConcurrentModificationException 解决办法
- java.util.ConcurrentModificationException! java.util.ConcurrentModificationException!
- java:java.util.ConcurrentModificationException
- 异常:java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException异常
- java.util.ConcurrentModificationException异常
- java.util.ConcurrentModificationException 解决办法
- java.util.ConcurrentModificationException 异常
- 异常:java.util.ConcurrentModificationException
- 异常:java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException 异常
- google protobuf
- 黑马程序员_java学习日记num17
- POJ 1018 离散最优化枚举
- 【C++学习】智能指针-shared_ptr
- BlocksKit源码分析(二)
- java.util.ConcurrentModificationException
- java可视化编程-eclipse安装windowbuilder插件
- Linux下练习C++的第一例
- Largest Rectangle in Histogram
- 调用android系统相机拍照并保存
- Spark Programming Guide 翻译
- 大端和小端
- 黑马程序员_java学习日记num18
- Spring MVC 下设置默认访问页面的3种方式