3

I'm finding conflicting advice over the best way to avoid a ConcurrentModificationException while doing this:

    List<Apple> Apples = appleCart.getApples();
    for (Apple apple : Apples)
    {
        delete(apple);
    }

I'm leaning towards using an Iterator in place of a List and calling its remove method.

Does that make the most sense here?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jonathan
  • 31
  • 2

5 Answers5

5

Yes, use an Iterator. Then you could use its remove method.

  for (Iterator<Apple> appleIterator = Apples.iterator(); appleIterator.hasNext();) {
     Apple apple = appleIterator.next();
     if (apple.isTart()) {
        appleIterator.remove();
     }
  }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
2

If you're getting a ConcurrentModificationException, you likely have multiple threads.

So the full answer includes both using Iterator.remove() and synchronizing access to the collection.

For example (where lock is synchronized on by all threads that may modify the list):

synchronized ( lock ) {
   List<Apple> apples = appleCart.getApples();
   for ( Iterator<Apple> it = apples.iterator(); it.hasNext(); )
   {
      Apple a = it.next(); 
      if ( a.hasWorm() ) {
         it.remove();
      }
   }
}
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
  • The code he posted will always throw ConcurrentModification regardless of concurrency issues. (Unless of course the list only has one element!) – Affe May 06 '11 at 18:40
  • In the OP's example, `ConcurrentModificationException` wouldn't involve multiple threads at all. It'd just be a result of removing from the list while iterating using its iterator. – ColinD May 06 '11 at 18:41
1
List<Apple> apples = appleCart.getApples();
for (Iterator<Apple> appleIterator = apples.iterator(); appleIterator.hasNext();)
{
   Apple apple = appleIterator.next();
   if ( apple.isYucky() ) {
     appleIterator.remove();
   }
}
Clint
  • 8,988
  • 1
  • 26
  • 40
0

Since Java 8 you can now do this: apples.removeIf(apple -> apple.equals(this))

Sam Orozco
  • 1,258
  • 1
  • 13
  • 27
0

You could keep a list of items to remove and then remove them after the loop:

List<Apple> apples = appleCart.getApples();
List<Apple> badApples = new ArrayList<Apple>();
for (Apple apple : apples) {
    if (apple.isBad()) {
        badApples.add(apple);
    } else {

    eat(apple);
}

apples.removeAll(badApples);
Isaac Truett
  • 8,734
  • 1
  • 29
  • 48