为什么这段代码不抛出ConcurrentModificationException?它Collection在不使用Iterator.remove()方法的情况下修改了一段时间,这是唯一安全的删除方法。
ConcurrentModificationException
Collection
Iterator.remove()
List<String> strings = new ArrayList<>(Arrays.asList("A", "B", "C")); for (String string : strings) if ("B".equals(string)) strings.remove("B"); System.out.println(strings);
如果将替换为ArrayList,则会得到相同的结果LinkedList。但是,如果我将列表更改为("A", "B", "C", "D)或只是("A", "B")得到了预期的异常。到底是怎么回事?我正在使用jdk1.8.0_25是否相关。
ArrayList
LinkedList
("A", "B", "C", "D)
("A", "B")
jdk1.8.0_25
编辑
我找到了以下链接
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4902078
相关部分是
天真的解决方案是将协同修改检查添加到AbstractList的hasNext中,但这会使协同修改检查的成本加倍。事实证明,仅在最后一次迭代上进行测试就足够了,这几乎没有增加任何成本。换句话说,hasNext的当前实现: public boolean hasNext() { return nextIndex() < size; } 替换为以下实现: public boolean hasNext() { if (cursor != size()) return true; checkForComodification(); return false; } 由于Sun内部监管机构拒绝了此更改,因此不会进行此更改。正式裁定表明,更改“表明了对现有代码产生重大兼容性影响的潜力”。(“兼容性影响”是该修复程序有可能用ConcurrentModificationException替换无声行为)。
天真的解决方案是将协同修改检查添加到AbstractList的hasNext中,但这会使协同修改检查的成本加倍。事实证明,仅在最后一次迭代上进行测试就足够了,这几乎没有增加任何成本。换句话说,hasNext的当前实现:
public boolean hasNext() { return nextIndex() < size; }
替换为以下实现:
public boolean hasNext() { if (cursor != size()) return true; checkForComodification(); return false; }
由于Sun内部监管机构拒绝了此更改,因此不会进行此更改。正式裁定表明,更改“表明了对现有代码产生重大兼容性影响的潜力”。(“兼容性影响”是该修复程序有可能用ConcurrentModificationException替换无声行为)。
通常,ConcurrentModificationException在 检测到 修改时引发s ,而不 引起 。如果修改后从未访问过迭代器,则不会引发异常。ConcurrentModificationException不幸的是,这一微小的细节使它对于检测数据结构的滥用非常不可靠,因为它们仅在损坏完成后才抛出。
这种情况不会抛出a,ConcurrentModificationException因为next()修改后不会在创建的迭代器上调用它。
next()
For-each循环实际上是迭代器,因此您的代码实际上如下所示:
List<String> strings = new ArrayList<>(Arrays.asList("A", "B", "C")); Iterator<String> iter = strings.iterator(); while(iter.hasNext()){ String string = iter.next(); if ("B".equals(string)) strings.remove("B"); } System.out.println(strings);
考虑您的代码在您提供的列表上运行。迭代看起来像:
hasNext()
strings
因此,ConcurrentModificationException当调用next()检测到进行了修改时抛出s时,此方案几乎避免了此类异常。
对于您的其他两个结果,我们确实有例外。对于"A", "B", "C", "D",删除“ B”之后,我们仍然处于循环中,并next()检测到ConcurrentModificationException,而对于"A", "B"我来说,它是某种ArrayIndexOutOfBounds被捕获并重新抛出为ConcurrentModificationException
"A", "B", "C", "D"
"A", "B"