为什么ArrayList.remove不起作用

时间:2013-10-19 02:19:21

标签: java arraylist

我有以下代码 -

import java.util.ArrayList;

public class ArrayListExp{
    public static void main (String[] args){

        ArrayList<String> name = new ArrayList<String>();

        name.add("Chris");
        name.add("Lois");
        name.add("Meg");
        name.add("Meg");
        name.add("Brain");
        name.add("Peter");
        name.add("Stewie");

        System.out.println(name);

        for ( int i = 0;  i < name.size(); i++){
            String oldName = name.get(i);
            if(oldName.equals("Meg"))
            {
                name.remove(i);
            }
        }

        System.out.println(name);
    }
}

但是这里它给了我输出 -

[Chris, Lois, Meg, Meg, Brain, Peter, Stewie]
[Chris, Lois, Meg, Brain, Peter, Stewie]

我没有明白这一点,为什么这不是删除Meg但是我只尝试了一个Meg,在这种情况下它正在运行。而当我在最后添加更多Meg时,Meg中的ArrayList未从{{1}}中删除。为什么呢?

7 个答案:

答案 0 :(得分:23)

删除第一个“Meg”时,索引i=2。然后它会递增,但由于其中一个“Meg”已被删除,现在name.get(3)是“Brain”。所以你实际上没有检查第二个“Meg”。

解决问题。您可以在删除元素时递减索引:

public class ArrayListExp{
    public static void main (String[] args){

        ArrayList<String> name = new ArrayList<String>();

        name.add("Chris");
        name.add("Lois");
        name.add("Meg");
        name.add("Meg");
        name.add("Brain");
        name.add("Peter");
        name.add("Stewie");

        System.out.println(name);

        for ( int i = 0;  i < name.size(); i++){
            String oldName = name.get(i);
            if(oldName.equals("Meg"))
            {
                name.remove(i);
                i--;
            }
        }

        System.out.println(name);
    }
}

答案 1 :(得分:5)

您正在迭代第一个Meg,当删除Meg时,数组值会移一。

[Chris, Lois, Meg, Meg, Brain, Peter, Stewie]
   0     1     2    3     4      5       6

第一个Meg被删除,并且循环递增i因为它完成了for循环中的所有内容的执行,因此i现在将为3并且数组已被修改:

[Chris, Lois, Meg, Brain, Peter, Stewie]
   0     1     2     3      4      5      

尝试向后迭代。

for ( int i = name.size() - 1;  i >= 0; i--){
    String oldName = name.get(i);
    if(oldName.equals("Meg"))
    {
        name.remove(i);
    }
}

答案 2 :(得分:4)

您可以使用name.removeAll(Arrays.asList("Meg"));删除所有"Meg"

您的完整代码将是

for ( int i = 0;  i < name.size(); i++){
    String oldName = name.get(i);
    if(oldName.equals("Meg"))
    {
       name.removeAll(Arrays.asList("Meg"));
    }
}

答案 3 :(得分:1)

你在从0到N迭代时从ArrayList中移除,所以当你在索引N处移除第一个Meg时,下一个Meg向下移动到索引N,然后你将i递增到N + 1。所以第二梅格不会被删除。尝试以相反的顺序迭代(N到0):

for ( int i = name.size() - 1;  i >= 0; i--) {

答案 4 :(得分:1)

因为当i = 2且条件为真时,删除meg并且所有索引都向上移动。因此下一个我会指向Brain,而不是meg。

试试这个。 (如果条件成立,则将i减1)

for ( int i = 0;  i < name.size(); i++){
            String oldName = name.get(i);
            if(oldName.equals("Meg"))
            {
                name.remove(i);
                i--;
            }
        }

答案 5 :(得分:0)

删除元素时不应使用for循环。在实现某些逻辑时总会出现问题。为您的问题使用反向循环,并始终尝试使用每个。

答案 6 :(得分:0)

Java 8 +

Collection接口现在提供了一种removeIf方法,该方法可以对其进行适当的修改,如果要删除该元素,您可以提供一个返回true的谓词。

因此,您可以像这样使用lambda:

name.removeIf(name -> name.equals("Meg"));

也可以使用方法参考以使其更加简洁。如果有null个元素,以下代码也将起作用。

name.removeIf("Meg"::equals);

如果您不想修改旧列表,则可以使用Streamfilter通过排除条件来获取应保留的所有项目的List。 / p>

final List<String> filtered = name.stream()
      .filter(name -> !"Meg".equals(name))
      .collect(Collectors.toList());

如果您特别需要ArrayList,请使用Collectors.toCollection和构造函数引用代替。

final ArrayList<String> filtered = name.stream()
       .filter(name -> !"Meg".equals(name))
       .collect(Collectors.toCollection(ArrayList::new));

Java 8之前的版本

问题是ArrayList在迭代时被修改,这会改变其大小并向前移动后面的元素;如果有连续的元素需要删除,这是一个问题。每次删除元素时,都需要将索引减少一,因为该索引现在将引用下一个元素。

for (int i = 0; i < name.size(); i++) {
    String oldName = name.get(i);
    if (oldName.equals("Meg")) {
        name.remove(i);
        i--;//Important!
    }
}

向后循环也可以解决此问题,因为元素永远不会移动到尚未检查的位置。
for (int i = name.size() - 1; i >= 0; i--) {
    String oldName = name.get(i);
    if (oldName.equals("Meg")) {
        name.remove(i);
    }
}

通常,使用Iterator最适合这种操作,因为它支持在通过调用Iterator#remove进行迭代的同时删除元素。这也会修改List到位。对于更复杂的操作,请考虑使用ListIterator

final Iterator<String> it = name.iterator();
while(it.hasNext()){
    final String name = it.next();
    if(name.equals("Meg")){
         it.remove();
    }
}