3

CopyOnWriteArrayList

迭代器不支持 remove 方法。

但是为什么它在增强的for循环中起作用?

List<String> lst = new CopyOnWriteArrayList<>();
lst.add("one"); 
lst.add("two"); 
lst.add("three"); 


for (String str : lst) { 
    if (str.equals("one")) { 
        lst.remove("two");   // no ConcurrentModificationException      
    } 
}        

System.out.println(lst);   // [one, three] => removed "two" !

List<String> lst = new ArrayList<>();会产生ConcurrentModificationException

Javadoc 明确指出CopyOnWriteArrayList.iterator()不支持remove()=> 它将抛出UnsupportedOperationException!我知道它是弱一致的 -如果我在从CopyOnWriteArrayList获得迭代器后将ConcurrentModificationException元素添加到CopyOnWriteArrayList

PS对不起,我不专心-我不在迭代器上调用了remove()!我对在增强型内部感到困惑(它隐式使用迭代器)。

4

2 回答 2

3

CopyOnWriteArrayList 迭代器故障安全实现支持修改操作。

当您迭代 CopyOnWriteArrayList 和 CopyOnWriteArraySet 时,迭代器使用基础列表(或集合)的快照,并且在创建快照后不会反映对列表或集合的任何更改。迭代器永远不会抛出 ConcurrentModificationException。

阅读更多:https ://markusjais.com/java-concurrency-understanding-copyonwritearraylist-and-copyonwritearrayset/

顺便说一句,在 ArrayList() 等经典 List 实现中,您不需要显式使用迭代器。使用 list.removeIf(predicate) 方法。

于 2019-09-06T19:36:08.373 回答
1

如果您尝试使用iteratorCopyOnWriteArrayList. 它会抛出异常。这就是 javadoc 想要表达的意思。

代码:

List<String> lst2 = new CopyOnWriteArrayList<String>();
lst2.add("one");
lst2.add("two");
lst2.add("three");

Iterator<String> iterator2 = lst2.iterator();
while (iterator2.hasNext()) {
    if (iterator2.next().equals("two")) {
        iterator2.remove();
    }
}
System.out.println(lst2.toString());

输出:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(CopyOnWriteArrayList.java:1178)
    at MyClass.main(MyClass.java:29)

但是,如果您在Arraylist. 它会正常工作。

来源:数组列表

代码:

List<String> lst = new ArrayList<String>();
lst.add("one");
lst.add("two");
lst.add("three");

Iterator<String> iterator = lst.iterator();
while (iterator.hasNext()) {
    if (iterator.next().equals("two")) {
        iterator.remove();
    }
}
System.out.println(lst.toString());

输出:

[one, three]

虽然如果您不想使用迭代器,您可以只使用public boolean removeIf(Predicate<? super E> filter)它只是一行并提供与上述相同的输出。

lst.removeIf(n -> (n.equals("two")));
于 2019-09-06T19:55:41.077 回答