从列表中移除项

在循环访问列表时,我希望根据条件删除列表中的某个项。请参阅下面的代码。

这给了我一个 ConcurrentModification异常。

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

这怎么可能呢?

367336 次浏览

You need to use Iterator and call remove() on iterator instead of using for loop.

//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);

You can't and shouldn't modify a list while iterating over it. You can solve this by temporarely saving the objects to remove:

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

You cannot do it because you are already looping on it.

Inorder to avoid this situation use Iterator,which guarentees you to remove the element from list safely ...

List<Object> objs;
Iterator<Object> i = objs.iterator();
while (i.hasNext()) {
Object o = i.next();
//some condition
i.remove();
}
for (Iterator<String> iter = list.listIterator(); iter.hasNext(); ) {
String a = iter.next();
if (...) {
iter.remove();
}
}

Making an additional assumption that the list is of strings. As already answered, an list.iterator() is needed. The listIterator can do a bit of navigation too.

–---------

Update

As @AyushiJain commented, there is

list.removeIf(...);

Besides all the excellent solutions offered here I would like to offer a different solution.

I'm not sure if you're free to add dependencies, but if you can, you could add the https://code.google.com/p/guava-libraries/ as a dependency. This library adds support for many basic functional operations to Java and can make working with collections a lot easier and more readable.

In the code I replaced the type of the List by T, since I don't know what your list is typed to.

This problem can with guava be solved like this:

List<T> filteredList = new Arraylist<>(filter(list, not(XXX_EQUAL_TO_AAA)));

And somewhere else you then define XXX_EQUAL_TO_AAA as:

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

However, this is probably overkill in your situation. It's just something that becomes increasingly powerful the more you work with collections.

Ohw, also, you need these static imports:

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