46
    for (String fruit : list)
    {
        if("banane".equals(fruit))
            list.remove(fruit);
        System.out.println(fruit);
    }

Here a loop with remove instruction. At execution time, I get some ConcurrentModificationException, below the console output:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
at java.util.AbstractList$Itr.next(AbstractList.java:420)
at Boucle.main(Boucle.java:14)
abricot
banane

Question: How to remove some element with a loop?

Jason C
  • 38,729
  • 14
  • 126
  • 182
enguerran
  • 3,193
  • 3
  • 26
  • 42

7 Answers7

100

You need to use the iterator directly, and remove the item via that iterator.

for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String fruit = iterator.next();
    if ("banane".equals(fruit)) {
        iterator.remove();
    }
    System.out.println(fruit);
}
Bombe
  • 81,643
  • 20
  • 123
  • 127
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • For the one who will recognize himself : don't use for with incremental index and list.size() !! I wanted to change the code with a foreach loop and it was not the correct soluce. Yours is the one. – enguerran Dec 17 '09 at 11:39
  • 1
    just change `it.hasNext()` to `iterator.hasNext()` and it's perfect! (obvious.... but who knows....) – user85421 Dec 17 '09 at 12:10
14

This seems a bit complicated, why not just do a normal for loop? I think it looks cleaner and won't throw this error. Just decriment i if you remove something. at least mine works, anyway. Those sort of auto-loops are more for coding convenience, I thought, so if they aren't being convenient then just don't use them.

for (int i = list.size() - 1; i>=0; i--) {
    String fruit = list.get(i);
    System.out.println(fruit);

    if ("banane".equals(fruit)) {
        list.remove(fruit);
    }
}
NotGaeL
  • 8,344
  • 5
  • 40
  • 70
steaiii
  • 141
  • 1
  • 2
  • 4
    This would be very slow (`O(n^2)` in algorithms terminology) on a large list, since `List#remove(Object)` needs to redo work by performing a linear search through the list for the given object. Better to use the index if possible, that will make it `O(n)` time. – Vicky Chijwani Aug 22 '18 at 20:27
7

In addition to using the Iterator directly (which I would recommend) you can also store elements that you want to remove in a different list.

List<String> toRemove = new ArrayList<String>();
for (String fruit : list) {
    if ("banane".equals(fruit))
        toRemove.add(fruit);
    System.out.println(fruit);
}
for (String fruit : toRemove) {
    list.remove(fruit);
}

Mind you, I do not recommend this, it’s just an alternative. :)

Bombe
  • 81,643
  • 20
  • 123
  • 127
5

Use a for loop, and loop over the collection in a reverse order. (That means, start with the last element, and loop to the first element. By doing so, you won't get problems by the indexes that change because of removing elements from the collection.

You get the exception in the example that you post, because the list over which your iterator iterates, has changed, which means that the iterator becomes invalid.

Frederik Gheysels
  • 56,135
  • 11
  • 101
  • 154
  • sounds dangerous. How about doubly-linked list and the like, where memory is not contiguous ? I don't know if lists et al have `index` in Java, or how `iterator` is implemented, but if it's like C++, I would be surprised if your approach have worked with anything except `ArrayList`. – Alexander Malakhov Oct 09 '13 at 11:49
4
for(Iterator<String> iter = list.iterator(); iter.hasNext(); )
{
   String fruit = iter.next();
   if("banana".equals(fruit))
      iter.remove();
   System.out.println(fruit);
}
Itay Maman
  • 30,277
  • 10
  • 88
  • 118
1

Similar to what Bombe suggested, but in less lines of code by iterating on the list copy, but removing from the original list;

List<String> temp = new ArrayList<String>(list);
for (String fruit : temp)
{
    if("banane".equals(fruit))
        list.remove(fruit);
    System.out.println(fruit);
}

Personally I think this looks nicer than iterating with an iterator.

Tom Neyland
  • 6,860
  • 2
  • 36
  • 52
  • I would say this is bug prone.. having 2 lists where we dont need the second. Just my 2cents. – cheekoo May 17 '11 at 20:45
  • @cheekoo, I can see how it would use unnecessary memory, but I fail to see how a competent developer would introduce bugs using this method. – Tom Neyland May 18 '11 at 17:25
  • haha! I agree. But now you have started using conditional statements! "COMPETENT developer" ;) – cheekoo May 18 '11 at 17:41
  • 1
    This has unnecessary iterations. `new ArrayList(list)` will iterate over `list`. Then you iterate over it again with the `for` loop. – Steve Kuo Jun 20 '11 at 15:54
1
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String s = iter.next();

    if (s.equals("a")) {
        iter.remove();
    }
}

is the best approach..

Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300