从列表中删除项目

111

在遍历列表时,我希望根据某个条件从列表中删除一个项目。请参见以下代码。

这会给我一个ConcurrentModification异常。

for (Object a : list) {
    if (a.getXXX().equalsIgnoreCase("AAA")) {
        logger.info("this is AAA........should be removed from the list ");
        list.remove(a);
    }
}

这该怎么做呢?


5
在遍历列表时,不能删除列表中的元素。相反,应该复制一份列表并从复制的列表中删除元素,或者直接在迭代器中进行操作。 - thegrinner
3
在Java 8中,最有效的方法是使用列表上的removeIf(predicate)方法来实现此操作。 - Holly Cummins
6个回答

232
for (Iterator<String> iter = list.listIterator(); iter.hasNext(); ) {
    String a = iter.next();
    if (...) {
        iter.remove();
    }
}

假设列表是字符串类型,需要执行list.iterator()方法来遍历列表。同时,listIterator方法也可以进行一些导航操作。

---------

更新

正如@AyushiJain的评论,有一个

list.removeIf(...);

3
如果你使用Arrays.asList(arr)创建了列表,那么可能会抛出UnsupportedOperationException异常,因为Arrays.asList()方法返回的是一个不可修改的列表。在这种情况下,你可以使用List<E> myList = new ArrayList<>(Arrays.asList(arr))来创建一个可修改的列表,然后使用listIterator遍历这个列表。如果你想要使用Java 8中的removeIf()方法替换其他方法,同样需要先创建一个可修改的列表。 - BrownRecluse
1
从Java8开始,有一个名为removeIf(..)的方法,它可以按条件从列表中删除元素。 - Ayushi Jain

77
你需要使用Iterator并在iterator上调用remove(),而不是使用for循环。

33

由于您已经在循环中对其进行了遍历,因此无法这样做。

为了避免这种情况,请使用迭代器,它可以确保您安全地从列表中删除元素...

List<Object> objs;
Iterator<Object> i = objs.iterator();
while (i.hasNext()) {
   Object o = i.next();
  //some condition
    i.remove();
}

21

在迭代列表时,您不能也不应该修改它。您可以通过暂时保存要删除的对象来解决这个问题:

List<Object> toRemove = new ArrayList<Object>();
for(Object a: list){
    if(a.getXXX().equalsIgnoreCase("AAA")){
        toRemove.add(a);
    }
}
list.removeAll(toRemove);

为什么我不能在迭代列表时修改它,也不应该这样做? - alexventuraio
3
因为迭代器模式的工作方式所导致。如果迭代器引用的列表在不知情的情况下发生更改(尤其是大小),迭代器将会出现问题。 - André Stannek

7
除了这里提供的所有优秀解决方案,我想提供一种不同的解决方案。如果您可以添加依赖项,您可以添加https://code.google.com/p/guava-libraries/作为依赖项。该库为Java添加了许多基本的函数操作支持,可以使集合的操作变得更加容易和可读。在代码中,我将列表的类型替换为T,因为我不知道您的列表的类型是什么。使用guava可以这样解决这个问题:
List<T> filteredList = new Arraylist<>(filter(list, not(XXX_EQUAL_TO_AAA)));

在其他地方,您需要将XXX_EQUAL_TO_AAA定义为:

public static final Predicate<T> XXX_EQUAL_TO_AAA = new Predicate<T>() {
    @Override
    public boolean apply(T input) {
        return input.getXXX().equalsIgnoreCase("AAA");
    }
}

然而,在您的情况下,这可能有些过度。它只是在处理集合时变得越来越强大的东西。

哦,还有,您需要进行这些静态导入:

import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Collections2.filter;

5
//first find out the removed ones

List removedList = new ArrayList();
for(Object a: list){
    if(a.getXXX().equalsIgnoreCase("AAA")){
        logger.info("this is AAA........should be removed from the list ");
        removedList.add(a);

    }
}

list.removeAll(removedList);

4
为什么这么复杂... - m0skit0
4
不复杂,这是从另一个列表中删除一个列表的另一种方式。 - Makky
4
你在不必要的情况下创建了一个新对象,而且可能还循环了两次列表。 - m0skit0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接