此操作是否安全?如果不是,为了做同样的事情,如何编写代码?此操作是否安全?
Set<Object> set;
......
for (Object o: set) {
if (some_condition) {
set.remove(o);
}
}
此操作是否安全?如果不是,为了做同样的事情,如何编写代码?此操作是否安全?
Set<Object> set;
......
for (Object o: set) {
if (some_condition) {
set.remove(o);
}
}
不,它不是 - 因为您不允许修改您正在迭代的集合,而不是通过迭代器。有很多方法可以解决这个问题。这里有一个:
for (Iterator<Object> iterator = set.iterator(); iterator.hasNext();)
{
Object value = iterator.next();
if (someCondition)
{
iterator.remove();
}
}
另一种选择是建立项目的独立的列表中删除,然后将它们全部删除后你遍历集合:
List<Object> itemsToRemove = new ArrayList<Object>();
for (Object x in set)
{
if (someCondition)
{
itemsToRemove.add(x);
}
}
set.removeAll(itemsToRemove);
现在,它会抛出ConcurrentModificationException
。
的for()
循环使用的Iterator
内部,保持一个编辑计数和如果编辑计数不匹配的后盾Set
的编辑数量,它抛出一个ConcurrentModificationException
当然,这取决于实际执行收集,但这是记录的行为,例如在the HashSet
docs:
此类的 iterator方法返回的迭代器是快速失败的:如果 组随时修改后的 迭代器是通过迭代器自身的移除 创建的,以任何方式,除了 方法,
Iterator
将抛出一个ConcurrentModificationException
。因此, 并发 修改的,迭代器很快就会完全失败 ,而不是 在 未来不确定的时间冒着任意的,非确定性 行为。
否 - 您的条件首次通过时,您会在下一次迭代中获得ConcurrentModificationException
。
在一般情况下,它是不是安全的直接修改集合在遍历它,和迭代器是在这种情况下,“快速失败”(因为整体上,而他们可以检测到的变化,有没有通用方式弄清楚如何应对他们)。
在这种情况下,一个工作的习惯用法是使用迭代器自己的remove()
方法。删除元素在这个可控的方式不断迭代知道发生了什么,并有碰巧迭代顺序什么一致的语义,所以可以作为你所期望的:
Iterator<Object> iter = set.iterator();
while (iter.hasNext()) {
final Object o = iter.next();
if (some_condition) {
iter.remove();
}
}
然而要注意remove()
是“可选操作”,并非所有集合的迭代器都支持它。如果你坚持在这种情况下,这将始终工作是采取集的副本替代,遍历是从原集删除的对象,像这样:
Set<Object> copy = new HashSet<Object>(set);
for (Object o: copy) {
if (some_condition) {
set.remove(o);
}
}
因为迭代超过copy
,而修改发生在set
,所以没有发生并发修改,并且迭代器很满意。
这就是“总是工作“,只要设置支持删除一般,当然:) – 2011-02-01 17:31:09
很好的解释! – peakit 2011-02-01 17:37:35
Set<Object> set;
......
Set<Object> objectsToBeDeleted = new HashSet<Object>();
for (Object o : set) {
if (some_condition) {
objectsToBeDeleted.add(o);
}
}
for (Object o : objectsToBeDeleted) {
set.remove(o);
}
第一句:*因为你不是很多*? – 2011-02-01 17:33:59