循环访问集合,避免在循环中删除对象时并发处理异常

2022-08-31 03:56:07

我们都知道您不能执行以下操作,因为: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

即使多个线程没有这样做。无论如何。

这个问题的最佳解决方案是什么?如何在循环中从集合中删除项而不引发此异常?

我在这里也使用任意的,不一定是一个,所以你不能依赖。CollectionArrayListget


答案 1

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 > The Collection Interface


同样,如果你有一个并且想要添加项目,你可以使用ListIterator#add,原因与你可以使用的原因相同 - 它被设计为允许它。ListIteratorIterator#remove


在您的情况下,您尝试从列表中删除,但如果尝试在迭代其内容的同时,则适用相同的限制。putMap


答案 2

这有效:

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

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