111

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?

Lii
  • 11,553
  • 8
  • 64
  • 88
Techie
  • 1,611
  • 3
  • 15
  • 24
  • 5
    You cannot remove an element from a list while you're iterating over said list. Make a copy and remove items from that instead, or do it directly to the iterator. – thegrinner Jun 24 '13 at 15:43
  • 3
    With Java 8, the most effective way to do this is use the removeIf(predicate) method on the list. – Holly Cummins Apr 23 '18 at 20:12

6 Answers6

231
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(...);
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • 3
    This might throw an UnsupportedOperationException if you have your list formed from Arrays.asList(arr) because Arrays.asList() gives you a fixed list. In that case, do an List myList = new ArrayList<>(Arrays.asList(arr)) and then use the listIterator over the list. Same goes if you want to replace the other with the Java 8 method of using removeIf()... – BrownRecluse Sep 08 '19 at 17:58
  • 1
    From Java8, there is a method - removeIf(..) which does the same thing that is remove elements from a list conditionally. – Ayushi Jain Feb 16 '22 at 10:55
77

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

kosa
  • 65,990
  • 13
  • 130
  • 167
33

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();
}
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
21

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);
André Stannek
  • 7,773
  • 31
  • 52
  • Why can't I and shouldn't I modify a list while iterating over it? – alexventuraio Oct 17 '16 at 16:43
  • 3
    @AlexVentura It's because of how the iterator pattern works. If the list the iterator references changes (especially it's size) without the iterator knowing, the iterator will be "messed up". – André Stannek Oct 18 '16 at 09:34
7

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;
Bart Enkelaar
  • 695
  • 9
  • 21
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);
Makky
  • 17,117
  • 17
  • 63
  • 86