List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
1. 使用fori
public static void main(String[] args) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals("1")) {
list.remove(i);
}
System.out.println("i: " + i + ", " + list.get(i));
}
System.out.println("list: " + list);
}
结果:
i: 0, 2
i: 1, 3
list: [2, 3]
分析:并不会抛异常:ConcurrentModificationException,但是2、3的索引产生改变。
2. 使用增强for
public static void main(String[] args) {
for (String str : list) {
if (str.equals("1")) {
list.remove(str);
}
}
System.out.println("list: " + list);
}
结果:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
at java.util.ArrayList$Itr.next(ArrayList.java:861)
public static void main(String[] args) {
for (String str : list) {
if (str.equals("2")) {
list.remove(str);
}
}
System.out.println("list: " + list);
}
结果:
list: [1, 3]
分析:
1. 为什么会抛异常:ConcurrentModificationException,源码里面是这样判断的:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
这里的两个值:modCount、expectedModCount,都是指数组修改次数,初始值为数组大小,本例中为3。
List的remove()方法只会增加modCount的值,而不会增加expectedModCount,具体实现如下:
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;
}
核心代码为fastRemove,
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; // clear to let GC do its work
}
如果删除的是元素1,调用remove方法后不会报错,但第二次循环的时候,调用next方法找第2个元素时,会调用checkForComodification,此时的modCount=4,而expectedModCount=3,故抛出此异常。
2. 为什么删除1抛异常,删除2不抛异常呢?
数组大小本来为3,删除元素2时,数组大小变为2了。元素2为倒数第二个,hasNext()时发现已没有下一个了(倒数第二个不会抛异常,其他位置均会抛异常),而数组大小也改变了,会重新初始化expectedModCount=modCount=2,故不会抛异常
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
.......
3. 使用iterator
Iterator<String> it = list.iterator();
while(it.hasNext()){
String x = it.next();
if(x.equals("1")){
it.remove();
}
}
结果:
list: [2, 3]
总结:使用iterator或list.removeIf(x -> x.equals("1"));
网友评论