遍历集合,在循环中删除对象时避免 ConcurrentModificationException

新手上路,请多包涵

我们都知道您不能执行以下操作,因为 ConcurrentModificationException

 for (Object i : l) {
    if (condition(i)) {
        l.remove(i);
    }
}

但这显然有时有效,但并非总是如此。下面是一些具体的代码:

 public static void main(String[] args) {
    Collection<Integer> l = new ArrayList<>();

    for (int i = 0; i < 10; ++i) {
        l.add(4);
        l.add(5);
        l.add(6);
    }

    for (int i : l) {
        if (i == 5) {
            l.remove(i);
        }
    }

    System.out.println(l);
}

这当然会导致:

 Exception in thread "main" java.util.ConcurrentModificationException

即使多个线程没有这样做。反正。

这个问题的最佳解决方案是什么?如何在不抛出此异常的情况下循环删除集合中的项目?

我在这里也使用任意 Collection ,不一定是 ArrayList ,所以你不能依赖 get

原文由 Claudiu 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 490
2 个回答

Iterator.remove() 是安全的,你可以这样使用它:

 List<String> list = new ArrayList<>();

// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
//     Iterator<String> iterator = list.iterator();
//     while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    if (string.isEmpty()) {
        // Remove the current element from the iterator and the list.
        iterator.remove();
    }
}

请注意 Iterator.remove() 是在迭代期间修改集合的唯一安全方法;如果在迭代过程中 以任何其他方式 修改基础集合,则行为未指定。

来源: docs.oracle > 集合接口


同样,如果您有一个 ListIterator 并且想要 添加 项目,您可以使用 ListIterator#add ,出于同样的原因,您可以使用 Iterator#remove 旨在允许–它。


在您的情况下,您尝试从列表中删除,但如果尝试将 put 放入 Map 同时迭代其内容,则同样的限制适用。

原文由 Bill K 发布,翻译遵循 CC BY-SA 4.0 许可协议

这有效:

 Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
    if (iter.next() == 5) {
        iter.remove();
    }
}

我认为由于 foreach 循环是迭代的语法糖,使用迭代器无济于事……但它为您提供了这个 .remove() 功能。

原文由 Claudiu 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题