93

I have the following piece of code:

private String toString(List<DrugStrength> aDrugStrengthList) {
    StringBuilder str = new StringBuilder();
        for (DrugStrength aDrugStrength : aDrugStrengthList) {
            if (!aDrugStrength.isValidDrugDescription()) {
                aDrugStrengthList.remove(aDrugStrength);
            }
        }
        str.append(aDrugStrengthList);
        if (str.indexOf("]") != -1) {
            str.insert(str.lastIndexOf("]"), "\n          " );
        }
    return str.toString();
}

When I try to run it, I get ConcurrentModificationException, can anyone explain why it happens, even if the code is running in same thread? And how could I avoid it?

Olimpiu POP
  • 5,001
  • 4
  • 34
  • 49
mabuzer
  • 6,497
  • 6
  • 35
  • 41
  • 1
    An explanation of this exception is that the iterator of the ArrayList is a fail-fast iterator; i.e. it will fail (throw exception) when it detects that its collection in the mean-time has been modified. In comparison to fail-safe iterators which don't throw concurrent modification exceptions (e.g. on collections ConcurrentHashMap and CopyOnWriteArrayList) – Mike Argyriou May 28 '14 at 12:05

6 Answers6

180

You can't remove from list if you're browsing it with "for each" loop. You can use Iterator. Replace:

for (DrugStrength aDrugStrength : aDrugStrengthList) {
    if (!aDrugStrength.isValidDrugDescription()) {
        aDrugStrengthList.remove(aDrugStrength);
    }
}

With:

for (Iterator<DrugStrength> it = aDrugStrengthList.iterator(); it.hasNext(); ) {
    DrugStrength aDrugStrength = it.next();
    if (!aDrugStrength.isValidDrugDescription()) {
        it.remove();
    }
}
Konrad Garus
  • 53,145
  • 43
  • 157
  • 230
  • the foreach syntax of java actually use Iterator, some IDE will report this solution and propose to replace with the foreach (for(MyListener listener : MyListenerList)) – Hugo Gresse Dec 29 '14 at 09:42
  • 1
    @HugoGresse Yes, but this is the opposite direction. Iterator exposes `remove` that is safe for its iteration, something that foreach "loses". – Konrad Garus Dec 30 '14 at 21:52
29

Like the other answers say, you can't remove an item from a collection you're iterating over. You can get around this by explicitly using an Iterator and removing the item there.

Iterator<Item> iter = list.iterator();
while(iter.hasNext()) {
  Item blah = iter.next();
  if(...) {
    iter.remove(); // Removes the 'current' item
  }
}
Edward Dale
  • 29,597
  • 13
  • 90
  • 129
23

I like a reverse order for loop such as:

int size = list.size();
for (int i = size - 1; i >= 0; i--) {
    if(remove){
        list.remove(i);
    }
}

because it doesn't require learning any new data structures or classes.

froman
  • 269
  • 2
  • 4
9

there should has a concurrent implemention of List interface supporting such operation.

try java.util.concurrent.CopyOnWriteArrayList.class

idiotgenius
  • 121
  • 1
  • 6
  • I had a same problem with HashMap, fixed with another implemention of Map interface. You should test it yourself.I don't know detail about CopyOnWriteArrayList – idiotgenius Jul 06 '10 at 13:35
8

While iterating through the loop, you are trying to change the List value in the remove() operation. This will result in ConcurrentModificationException.

Follow the below code, which will achieve what you want and yet will not throw any exceptions

private String toString(List aDrugStrengthList) {
        StringBuilder str = new StringBuilder();
    List removalList = new ArrayList();
    for (DrugStrength aDrugStrength : aDrugStrengthList) {
        if (!aDrugStrength.isValidDrugDescription()) {
            removalList.add(aDrugStrength);
        }
    }
    aDrugStrengthList.removeAll(removalList);
    str.append(aDrugStrengthList);
    if (str.indexOf("]") != -1) {
        str.insert(str.lastIndexOf("]"), "\n          " );
    }
    return str.toString();
}
bragboy
  • 34,892
  • 30
  • 114
  • 171
4

We can use concurrent collection classes to avoid ConcurrentModificationException while iterating over a collection, for example CopyOnWriteArrayList instead of ArrayList.

Check this post for ConcurrentHashMap

http://www.journaldev.com/122/hashmap-vs-concurrenthashmap-%E2%80%93-example-and-exploring-iterator