为什么这段代码不会抛出ConcurrentModificationException? [英] Why doesn't this code throw a ConcurrentModificationException?
问题描述
为什么这段代码不会抛出 ConcurrentModificationException
?它在迭代它时修改 Collection
,而不使用 Iterator.remove()
方法,这意味着唯一安全的删除方式。
Why doesn't this code throw a ConcurrentModificationException
? It modifies a Collection
while iterating through it, without using the Iterator.remove()
method, which is meant to be the only safe way of removing.
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 $ c $,我会得到相同的结果c>使用
LinkedList
。但是,如果我将列表更改为(A,B,C,D)
或只是(A, B)
我得到了预期的异常。发生了什么?我正在使用 jdk1.8.0_25
如果相关的话。
I get the same result if I replace the ArrayList
with a LinkedList
. However if I change the list to ("A", "B", "C", "D)
or just ("A", "B")
I get the exception as expected. What is going on? I am using jdk1.8.0_25
if that is relevant.
编辑
我找到了以下链接
http://bugs.java.com/bugdatabase /view_bug.do?bug_id=4902078
相关部分
天真的解决方案是在AbstractList中为hasNext添加编码检查,但这会使编纂检查的成本增加一倍。
事实证明只在最后的
迭代上进行测试就足够了,这几乎没有增加成本。换句话说,
当前实现的hasNext:
The naive solution is to add comodification checks to hasNext in AbstractList, but this doubles the cost of comodification checking. It turns out that it is sufficient to do the test only on the last iteration, which adds virtually nothing to the cost. In other words, the current implementation of hasNext:
public boolean hasNext() {
return nextIndex() < size;
}
替换为此实现:
public boolean hasNext() {
if (cursor != size())
return true;
checkForComodification();
return false;
}
由于Sun内部监管机构拒绝了此更改,因此不会进行此更改。正式裁决表明,该变更有b $ b b表明可能会对现有代码造成重大兼容性影响
。 (兼容性影响是修复具有
可能用
ConcurrentModificationException替换无声错误行为。)
This change will not be made because a Sun-internal regulatory body rejected it. The formal ruling indicated that the change "has demonstrated the potential to have significant compatibility impact upon existing code." (The "compatibility impact" is that the fix has the potential to replace silent misbehavior with a ConcurrentModificationException.)
推荐答案
作为一般规则,当检测到 时,抛出 ConcurrentModificationException
,而不是引起。如果您在修改后从未访问过迭代器,则不会抛出异常。遗憾的是,这个细节使得 ConcurrentModificationException
对于检测数据结构的滥用是相当不可靠的,因为它们仅在损坏完成后被抛出。
As a general rule, ConcurrentModificationException
s are thrown when the modification is detected, not caused. If you never access the iterator after the modification, it won't throw an exception. This minute detail makes ConcurrentModificationException
s rather unreliable for detecting misuse of data structures, unfortunately, as they only are thrown after the damage has been done.
此方案不会抛出 ConcurrentModificationException
,因为 next()
未被调用在修改后创建的迭代器上。
This scenario doesn't throw a ConcurrentModificationException
because next()
doesn't get called on the created iterator after the modification.
For-each循环实际上是迭代器,所以你的代码实际上是这样的:
For-each loops are really iterators, so your code actually looks like this:
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);
考虑在您提供的列表上运行的代码。迭代看起来像:
Consider your code running on the list you provided. The iterations look like:
-
hasNext()
返回true,输入循环, - > iter移动到索引0,字符串=A,未移除 -
hasNext()
返回true,继续循环 - > iter移动到索引1,字符串=B,删除。字符串
现在长度为2. -
hasNext()
返回false(iter)目前在最后一个索引,没有更多的索引去),退出循环。
hasNext()
returns true, enter loop, -> iter moves to index 0, string = "A", not removedhasNext()
returns true, continue loop -> iter moves to index 1, string = "B", removed.strings
now has length 2.hasNext()
returns false (iter is currently at the last index, no more indices to go), exit loop.
因此,作为 ConcurrentModificationException当
s,这种情况可以避免这种异常。 next()
的调用检测到已经进行了修改时,抛出
Thus, as ConcurrentModificationException
s are thrown when a call to next()
detects a that a modification has been made, this scenario narrowly avoids such an exception.
对于您的其他两个结果,我们会得到例外情况。对于A,B,C,D
,删除B后我们仍然在循环中,然后 ()
检测到 ConcurrentModificationException
,而对于A,B
我' d想象它是某种ArrayIndexOutOfBounds被捕获并重新抛出为 ConcurrentModificationException
For your other two results, we do get exceptions. For "A", "B", "C", "D"
, after removing "B" we are still in the loop, and next()
detects the ConcurrentModificationException
, whereas for "A", "B"
I'd imagine it's some kind of ArrayIndexOutOfBounds that's being caught and re-thrown as a ConcurrentModificationException
这篇关于为什么这段代码不会抛出ConcurrentModificationException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!