根据javadocs,当我们在迭代集合时尝试对集合进行结构修改时,将抛出conncurrent修改异常。只有迭代器删除方法不会引发并发修改异常。
我分析了以下不会抛出并发修改异常的情况:
List<Integer> var=new ArrayList<Integer>();
var.add(3);
var.add(2);
var.add(5);
第一种情况:
for(int i = 0; i<var.size(); i++){
System.out.println(var.get(i));
var.remove(i);
}
第二种情况:
for(Integer i:var){
System.out.println(i);
if(i==2){
var.remove("5");
}
}
1)谁能解释一下这些情况如何不抛出并发修改异常?2)任何人都可以告诉iterator.move内部是如何工作的吗?
根据 ArrayList
的 Javadoc :
此类的迭代器和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行结构修改,则除了通过迭代器自己的 remove 或 add 方法之外,迭代器将抛出 ConcurrentModificationException。
因此,抛出CME的条件是:
- 必须有一个迭代器(或列表迭代器)
- 您必须不通过迭代器对列表执行结构修改(即添加或删除元素)
而且,也许不是那么明显:
- 结构修改后,必须在结构修改之前创建的迭代器上调用方法。
即迭代器不会尝试检测 CME,直到您调用 next()
或在其上remove()
。
第一个实现没有使用迭代器,所以它当然不会抛出。 抛出的只有Iterator
(尽管即使是索引的for循环也会损坏,例如,如果您删除一个元素,然后所有其他元素的索引从迭代下移出)。 Java只是无法告诉你。
第二个实现不是更改内容。 var.remove("5")
尝试删除字符串"5"
,该字符串不存在(列表仅包含整数),因此不会发生任何更改。 此外,当i
是盒装大写字母时,i == 2
是危险的 - I
Integer
;考虑改为for (int i : var)
。
最后,没有实现保证会抛出ConcurrentModificationException
;它只是试图这样做来警告你的迭代器已被损坏。 无论是否抛出异常,迭代器都会因迭代过程中执行的修改而损坏,Java 只是试图警告您。