迭代期间哪些标准Java集合是可移除的?

时间:2012-05-18 11:46:37

标签: java

使用广泛使用的集合类型的for(Type x:collection){...}会在迭代期间删除x吗?

在JavaDocs中是否需要注意这个技术术语?

澄清:

我最初只询问使用for-each语法for(Type x:collection){...}。然而,更完整的答案将描述这种风格并使用基于迭代器的常规循环,其中存在差异......问题更多的是关于哪些标准集合允许我在迭代期间删除元素,以及如何执行迭代以允许这种情况。

3 个答案:

答案 0 :(得分:5)

一个这样的集合是CopyOnWriteArrayListjava.util.concurrent包中的其他集合共享此功能。

它们的迭代器永远不会抛出ConcurrentModificationException的事实是这个类的copy-on-write语义的副作用:每次修改它时,都会复制底层数组。这样做是为了允许快速并发访问经常读取但很少修改的列表。

JavaDoc就是这样解释的(强调我的):

  

“snapshot”样式迭代器方法在创建迭代器时使用对数组状态的引用。这个数组在迭代器的生命周期内永远不会改变,所以干扰是不可能的,并且保证迭代器不会抛出ConcurrentModificationException

除了更新的高成本之外,这种实现还有一些其他缺点:

  

自迭代器创建以来,迭代器不会反映列表的添加,删除或更改。不支持对迭代器本身(removesetadd)进行元素更改操作。这些方法抛出UnsupportedOperationException

请注意,这些集合意味着可以实现“简单”循环和删除,但是专用集合用于高并发性情况,其中许多线程需要并发访问仍然可以更改的数据(但通常很少更改)。 不要只需用ArrayList替换每个CopyOnWriteArrayList

答案 1 :(得分:0)

作为拇指的规则:名称中包含“并发或阻止”的任何内容。 ConcurrentLinkedListConcurrentSkipListSetLinkedBlockingDequeLinkedBlockingQueue等 keySet(),ConcurrentHashMap的值()和ConcurrentSkipListMap等等。 大多数java.util.concurrent都是ConcurrentModificationException,这很好。

COWArrayList通常对较小的集合或很少修改的集合很有用......你应该避免显式的set方法。

一个重要的注意事项:使用iterator.remove应该总是偏向于Collection.remove(除了CHM.entrySet(),这是一个错误的方式)[当可用时,COWArrayList迭代器不支持删除]。所有非随机访问结构都将受益于不必查找可能为O(n)的元素。

整体ConcurrentModificationException是一个半生不熟的想法及其影响。涉及一些副作用,包括。防止硬件事务内存运行。它带来了很少需要的额外性能成本。 HashMap有一个可怕的impl。 w / volatile modCount(在每次迭代时写入修改和读取,但在x86上读取是免费的)。

答案 2 :(得分:-1)

可能有点迟到的答案,但Java 8使得在迭代时从集合中删除元素变得更加容易:

removeIf(Predicate<? super E> filter)

删除此集合中满足给定谓词的所有元素。