异常内容
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at com.chen.chenarraylist.ChenTest.testRemove(ChenTest.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Process finished with exit code -1
异常代码
@Test
public void testRemove() {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
for (Integer integer : integers) {
// 删除小于2的元素
if (integer < 2) {
integers.remove(integer);
}
}
}
异常原因分析
查看异常输出,可以知道发生了java.util.ConcurrentModificationException
异常。刚刚遇到的时候有点懵逼。WC,怎么会出现这样的异常。其实只要看一下Iterator
的源码就可以解决这个问题。
//该函数的功能是新建一个成员内部类对象Iter
public Iterator<E> iterator() {
return new Itr();
}
Itr类的源代码
private class Itr implements Iterator<E> {
int cursor; // 下一个要返回的元素位置
int lastRet = -1; // 最后一个返回的索引位置,如果没有默认为-1
int expectedModCount = modCount;//期望修改次数
Itr() {}
//...省略其他方法
}
我们重点看一下next()
函数的源代码
public E next() {
//首先检测在迭代的过程中是否发生修改
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
其中checkForComodification()
的源代码为:
final void checkForComodification() {
//如果在迭代过程中发生修改,直接抛出ConcurrentModificationException异常,这正是我们异常提示所报的异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
综上,异常分析完毕。那如何解决呢?预知后事如何,且听下回分解。
异常解决思路
既然next()
函数会首先检查当前是否发生了结构性变化。那我们直接修改expectedModCount
即可。
修改后的代码:
@Test
public void testRemoveRight() {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
Iterator<Integer> iterator = integers.iterator();
while (iterator.hasNext()) {
// 删除小于2的元素
if (iterator.next() < 2) {
iterator.remove();
}
}
// 输出删除后的结果
iterator = integers.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
/**
* 运行结果:
* 2
* 3
* 成功将1删除
*/
}
总结
遇到问题不要慌,多看源码,问题慢慢就会解决。By the way、使用迭代器,需要访问容器元素的代码只需要一个Iterator接口的引用,不需要关注数据的实际组织方式,可以使用统一的方式进行访问。对代码设计很有帮助的哦!