在 Java 中的 foreach 循环中调用 remove

2022-08-31 04:10:24

在 Java 中,在使用 foreach 循环循环循环遍历集合时对集合调用 remove 是否合法?例如:

List<String> names = ....
for (String name : names) {
   // Do something
   names.remove(name).
}

作为附录,删除尚未迭代的项目是否合法?例如

//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
    // Do something
    while (names.remove(name));
}

答案 1

若要在迭代集合时安全地从集合中删除,应使用迭代器。

例如:

List<String> names = ....
Iterator<String> i = names.iterator();
while (i.hasNext()) {
   String s = i.next(); // must be called before you can call i.remove()
   // Do something
   i.remove();
}

Java 文档中

此类的迭代器和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行了结构修改,则除了通过迭代器自己的 remove 或 add 方法之外,迭代器将引发 ConcurrentModificationException。因此,面对并发修改,迭代器会快速干净地失败,而不是在未来不确定的时间冒着任意的非确定性行为的风险。

也许许多新手不清楚的是,使用for/foreach构造迭代列表会隐式创建一个必然无法访问的迭代器。此信息可以在这里找到


答案 2

你不想那样做。它可能会导致未定义的行为,具体取决于集合。您希望直接使用迭代器。尽管 for 每个构造都是语法糖,并且实际上使用迭代器,但它会从代码中隐藏它,因此您无法访问它来调用 Iterator.remove

如果在迭代过程中以调用此方法以外的任何方式修改了基础集合,则未指定迭代器的行为。

相反,请编写您的代码:

List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {

    String name = it.next();
    // Do something
    it.remove();
}

请注意,代码调用 的不是 。Iterator.removeList.remove

补遗:

即使您要删除尚未迭代的元素,您仍然不想修改集合,然后使用 .它可能会以一种令人惊讶的方式修改集合,并影响将来对 .IteratorIterator


推荐