While looping through a list, I would like to remove an item of a list depending on a condition. See the code below.
This gives me a ConcurrentModification exception.
for (Object a : list) {
if (a.getXXX().equalsIgnoreCase("AAA")) {
logger.info("this is AAA........should be removed from the list ");
list.remove(a);
}
}
How can this be done?
6 Answers
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(...);
You need to use Iterator and call remove() on iterator instead of using for loop.
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();
}
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);
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 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;
//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);