在Java中,您可以在迭代时修改List吗?

use*_*410 38 java arraylist

我理解在Java中,Collection<E>不应该在迭代它时修改它,例如删除或添加元素.但是如何更改List中的元素呢?例如,如果有的话

List<String> letters = new ArrayList<String>();
letters.add("A");
letters.add("B");
letters.add("C");
int i = 0;

for (String letter : letters) {
    letters.set(i, "D");
    i++;
}
Run Code Online (Sandbox Code Playgroud)

所以,我不是在谈论修改存储在元素中的对象; 我在谈论改变对象是什么.List的大小没有被改变,但索引处的对象正在改变,所以从技术上讲,List正在被修改.我的老板声称这段代码很好(而且看起来确实有效),但我仍然认为它不正确.使用ListIterator的set(E e)方法的另一种方法是更好吗?

Ósc*_*pez 39

在遍历它时修改列表中的元素的想法没有错(不要修改列表本身,不建议这样做),但它可以更好地表达如下:

for (int i = 0; i < letters.size(); i++) {
    letters.set(i, "D");
}
Run Code Online (Sandbox Code Playgroud)

最后,整个列表将以字母"D"为内容.for在这种情况下使用增强循环并不是一个好主意,你不会将迭代变量用于任何东西,而且你不能使用迭代变量修改列表的内容.

请注意,上面的代码段没有修改列表的结构 - 意思是:没有添加或删除元素,列表的大小保持不变.简单地将一个元素替换为另一个元素并不算作结构修改.这是@ZouZou在评论中引用的文档的链接,它指出:

结构修改是添加或删除一个或多个元素或显式调整后备数组大小的任何操作; 仅设置元素的值不是结构修改

  • +1如果使用CopyOnWriteArrayList,则可以在迭代时修改它. (6认同)

小智 12

使用CopyOnWriteArrayList
,如果要删除它,请执行以下操作:

for (Iterator<String> it = userList.iterator(); it.hasNext() ;)
{
    if (wordsToRemove.contains(word))
    {
        it.remove();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • CopyOnWriteArrayList 返回一个不支持 remove() 方法的迭代器。请参阅 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html#iterator() (3认同)
  • 此答案是从列表中删除不是问题答案的项目。问题是如何在迭代时替换/更新/交换列表中的项目。 (2认同)

Luk*_*uke 8

Java 8 的stream()界面提供了一种就地更新列表的好方法。

要安全地更新列表中的项目,请使用map()

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

// add stuff to list

letters = letters.stream().map(x -> "D").collect(Collectors.toList());

Run Code Online (Sandbox Code Playgroud)

要安全地移除物品,请使用filter()


letters.stream().filter(x -> !x.equals("A")).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 在描述中写入“就地”两次并不会使这些行对列表进行就地修改。`Collectors.toList()` 为您创建一个全新的列表,然后在第一个示例中将其存储在 `letters` 中,并在第二个示例中简单地丢弃。 (13认同)