以下模型代码最终在ConcurrentModificationException
中发生(正如我理解的那样),因为我正在迭代一个我正在修改的集合。
Set<String> data = new HashSet<String>();
data.add("a=1");
data.add("b=2");
data.add("c=3");
data.add("d=4");
for (String s : data) {
data.remove(s);
}
但为什么呢?请帮助澄清
答案 0 :(得分:2)
抛出异常只是因为你在迭代它时修改了集合(通过调用data.remove(s)
)。 Java Collections通常要求在迭代它们的值时不能修改它们。
一个线程通常不允许修改Collection,而另一个线程正在迭代它。通常,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此异常。执行此操作的迭代器称为失败快速迭代器,因为它们快速而干净地失败,而不是在未来的未确定时间冒着任意的,非确定性行为的风险。
答案 1 :(得分:2)
您违反了迭代器的合同 。来自ConcurrentModificationException
javadoc,
如果单个线程发出一系列方法调用 违反对象的合同,对象可能抛出这个 例外。例如,如果线程直接修改集合 而它使用快速失败的迭代器迭代集合, 迭代器将抛出此异常。
答案 2 :(得分:1)
您必须使用Iterator从Set
中删除元素答案 3 :(得分:1)
这是因为编译器实际上插入了Iterator
,然后使用传统的for循环迭代元素。如果修改迭代器所在的Collection
,则会导致未确定的行为。为了防止这种情况,抛出ConcurrentModificationException
。
另见here:
项目7.不要在迭代期间修改列表。虽然for-each语法不提供对等效基本for循环使用的迭代器的直接访问,但可以通过直接调用列表中的其他方法来修改列表。这样做可能会导致不确定的程序行为。特别是,如果对iterator()的编译器插入调用返回一个故障快速迭代器,则可能抛出java.util.ConcurrentModificationException运行时异常。但这只是尽力而为,除非作为在异常被抛出时检测错误的手段,否则不能依赖它。
或Language Specification中每个循环的部分。