2011-08-30 186 views
2

以下样机代码在ConcurrentModificationException结束,发生(根据我的理解),由于我正在迭代一套,我正在修改的事实。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); 
} 

但是,为什么到了?请帮忙澄清

回答

2

您违反合同迭代器的。从ConcurrentModificationException javadoc

如果单个线程发出的方法调用序列 违反对象的合同,该对象可能抛出此 例外。例如,如果一个线程直接修改集合 而迭代器使用快速迭代器迭代该集合,则迭代器将抛出此异常。

+0

而这样做的原因是,快速失败优于“在未来某个未定的时间冒着任意的,非确定性行为的风险”。 (同一文件) –

+0

@Kublai Khan,感谢您的阐述,但我故意忽略包括那部分,因为我包含的片段已经足够。 – mre

+0

因为这是为什么我认为会有帮助的问题。 -shrug- –

1

你必须使用迭代器从一组

+0

我认为OP在问为什么。 –

2

仅仅是因为要修改的集合(通过调用data.remove(s)),异常被抛出删除元素同时遍历它。 Java集合通常要求在迭代它们的值时不能修改它们。

official documentation

它不是一般允许一个线程修改集合,而另一个线程上进行迭代。一般来说,在这些情况下迭代的结果是不确定的。某些迭代器实现(包括由JRE提供的所有通用集合实现的实现)可能会选择在检测到此行为时抛出此异常。这样做的迭代器被称为快速迭代器,因为它们快速且干净地失败,而在将来未定的时间冒着任意的,非确定性的行为冒险。

1

这是因为编译器实际上插入了Iterator,然后使用传统的for循环遍历元素。如果修改迭代器创建的Collection,则会导致未确定的行为。为了防止这种情况,引发ConcurrentModificationException

here参见:

项目7.迭代过程中不要修改该列表。虽然for-each语法不能直接访问由等价基本for循环使用的迭代器,但可以通过直接调用列表中的其他方法来修改列表。这样做会导致不确定的程序行为。特别是,如果编译器插入的对iterator()的调用返回一个快速失败的迭代器,则可能会抛出java.util.ConcurrentModificationException运行时异常。但是,这只能以尽力而为的方式完成,除非作为在发生异常时检测错误的手段,否则不能被依赖。

或在Language Specification中的每个循环的部分。