簡體   English   中英

為什么CopyOnWriteArrayList的迭代器允許在enhanced-for循環中使用remove(),而它的迭代器不支持remove()操作?

[英]Why CopyOnWriteArrayList's iterator allows remove() in enhanced-for loop, while its iterator does not support remove() operation?

的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獲取迭代器之后向CopyOnWriteArrayList添加元素時沒有ConcurrentModificationException

PS 抱歉,我不專心 - 我沒有在迭代器上調用remove()! 我被置於增強型內部(它隱式使用迭代器)而感到困惑。

CopyOnWriteArrayList迭代器失敗安全實現支持修改操作。

迭代CopyOnWriteArrayList和CopyOnWriteArraySet時,迭代器使用基礎列表(或集)的快照,並且在創建快照后不反映對列表或集的任何更改。 迭代器永遠不會拋出ConcurrentModificationException。

欲了解更多信息, 訪問: https//markusjais.com/java-concurrency-understanding-copyonwritearraylist-and-copyonwritearrayset/

順便說一句,在像ArrayList()等經典List實現中,您不需要顯式使用迭代器。 使用list.removeIf(謂詞)方法。

如果您嘗試使用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上做同樣的事情。 它會工作正常。

來源: 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")));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM