调用在Java中的foreach循环中删除


Answers

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

如果除了通过调用此方法以外的任何其他方式进行迭代时修改了底层集合,则未指定迭代器的行为。

请写下你的代码:

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

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

请注意,代码调用Iterator.remove ,而不是List.remove

附录:

即使您要删除尚未迭代的元素,仍然不想修改集合,然后使用Iterator 。 它可能会以令人惊讶的方式修改集合,并影响Iterator未来操作。

Question

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



确保这不是代码味道。 是否有可能扭转逻辑,并且是'包容'而不是'排他'?

List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
   // Do something
   if (conditionToIncludeMet)
       reducedNames.add(name);
}
return reducedNames;

导致我访问此页面的情况涉及使用indecies从列表中移除元素的旧代码。 我想重构它来使用foreach风格。

它遍历整个元素列表以验证用户有权访问哪些元素,并删除那些没有来自列表的权限的元素。

List<Service> services = ...
for (int i=0; i<services.size(); i++) {
    if (!isServicePermitted(user, services.get(i)))
         services.remove(i);
}

为了反转这个并且不使用remove:

List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
    if (isServicePermitted(user, service))
         permittedServices.add(service);
}
return permittedServices;

什么时候“删除”是首选? 其中一个考虑因素是,如果列表大小较大或昂贵的“添加”,加上与列表大小相比只有少量删除。 只做一些删除而不是添加很多补充可能更有效。 但就我而言,情况并不适合这样的优化。




for (String name : new ArrayList<String>(names)) {
    // Do something
    names.remove(nameToRemove);
}

在从原始列表中删除时,克隆列表names并遍历克隆。 比顶部的答案更清洁一点。




当您想从列表中移除元素时,最好使用Iterator

因为删除的源代码是

if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
elementData[--size] = null;

所以,如果你从列表中删除一个元素,列表将被重新构造,另一个元素的索引将被改变,这可能会导致你想要发生的事情。




是的,您可以使用for-each循环,为此,您必须维护一个单独的列表来保存删除项目,然后使用removeAll()方法从名称列表中删除该列表,

List<String> names = ....

// introduce a separate list to hold removing items
List<String> toRemove= new ArrayList<String>();

for (String name : names) {
   // Do something: perform conditional checks
   toRemove.add(name);
}    
names.removeAll(toRemove);

// now names list holds expected values



Related