这个操作安全吗?

发布于 2024-10-15 11:13:50 字数 175 浏览 4 评论 0原文

这个操作安全吗? 如果没有,为了做同样的事情,如何编写代码?

Set<Object> set;

......

for (Object o: set) {
    if (some_condition) {
        set.remove(o);
    }
}

Is this operation safe?
if not, in order to do the same thing, how to write the code??

Set<Object> set;

......

for (Object o: set) {
    if (some_condition) {
        set.remove(o);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

葬花如无物 2024-10-22 11:13:50

不,不是 - 因为除了通过迭代器之外,您不允许修改正在迭代的集合。有多种选项可以解决此问题。这是一个:

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);

No, it's not - because you aren't allowed to modify a collection you're iterating over, other than via the iterator. There are various options for fix this. Here's one:

for (Iterator<Object> iterator = set.iterator(); iterator.hasNext(); )
{
    Object value = iterator.next();
    if (someCondition)
    {
        iterator.remove();
    }
}

Another option is to build a separate list of items to remove, and then remove them all after you've iterated over the set:

List<Object> itemsToRemove = new ArrayList<Object>();
for (Object x in set)
{
    if (someCondition)
    {
        itemsToRemove.add(x);
    }
}

set.removeAll(itemsToRemove);
萌辣 2024-10-22 11:13:50

否 - 第一次通过条件时,您将在下一次迭代中抛出 ConcurrentModificationException

一般来说,在迭代集合时直接修改集合是不安全的,并且迭代器在这种情况下是“快速失败”的(因为总的来说,虽然它们可以检测更改,但没有通用的方法找出如何应对它们)。

在这种情况下,一种有效的习惯用法是使用 Iterator 自己的 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上,所以不会发生并发修改,迭代器很高兴。

No - the first time your condition passes, you'll get a ConcurrentModificationException thrown on the next iteration.

In general, it is not safe to modify a collection directly while iterating over it, and iterators are "fail-fast" in this situation (because on the whole while they can detect changes, there's no general way to work out how to cope with them).

In this situation, one idiom that does work is to use the Iterator's own remove() method. Removing the element in this controlled fashion keeps the iterator aware of what is happening, and has consistent semantics for what should happen to the iteration order, and so works as you would expect:

Iterator<Object> iter = set.iterator();
while (iter.hasNext()) {
   final Object o = iter.next();
   if (some_condition) {
      iter.remove();
   }
}

Note however that remove() is an "optional operation", and not all collections' iterators support it. If you're stuck in this situation, an alternative that will always work is to take a copy of the set, iterate over that and remove the objects from the original set, like so:

Set<Object> copy = new HashSet<Object>(set);
for (Object o: copy) {
    if (some_condition) {
        set.remove(o);
    }
}

Because the iteration is over copy, while the modifications happen to set, no concurrent modification occurs and the iterator is happy.

兮子 2024-10-22 11:13:50

现在,它将抛出一个ConcurrentModificationException

for() 循环在内部使用 Iterator 来保存编辑计数,如果该编辑计数与支持 Set 的编辑不匹配计数,它会抛出一个 ConcurrentModificationException

当然这取决于集合的实际实现,但这是记录的行为,例如在 HashSet 文档

该类返回的迭代器
迭代器方法是快速失败的:如果
设置后可以随时修改
迭代器以任何方式创建,除了
通过迭代器自己的remove
方法时,Iterator 抛出一个
ConcurrentModificationException。因此,
面对并发
修改,迭代器失败
快速而干净地,而不是
冒任意性、不确定性的风险
在不确定的时间的行为
未来。

Now, it will throw a ConcurrentModificationException.

The for() loop uses an Iterator internally that keeps an edit count and if that edit count doesn't match the backing Set's edit count, it throws a ConcurrentModificationException

Of course this depends on the actual implementation of the collection, but that's the documented behavior, e.g. in the HashSet docs:

The iterators returned by this class's
iterator method are fail-fast: if the
set is modified at any time after the
iterator is created, in any way except
through the iterator's own remove
method, the Iterator throws a
ConcurrentModificationException. Thus,
in the face of concurrent
modification, the iterator fails
quickly and cleanly, rather than
risking arbitrary, non-deterministic
behavior at an undetermined time in
the future.

鹤舞 2024-10-22 11:13:50
    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);
    }
    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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文