Remove item from a collection

Asked

Viewed 186 times

2

Why is it considered incorrect to remove an object from a collection in this way? And why the exception launch ConcurrentModificationException?

for(String item: list) {
  list.remove(item);
}

2 answers

4

why the launch of the exception ConcurrentModificationException?

This exception is launched because it is a mechanism of fail-fast for cases where there is any modification in the collection that we are iterating.

In other words, before "in fact" gives problem, in case there is any modification in the collection, the Trigger exception.


To get around this, you can make use of the Iterator.
In fact, the for each uses the Iterator under the covers, but to be less verbose, it "hides" the full code and you don’t need to type everything always.

To solve the problem you can do something like:

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String item = iterator.next();
    iterator.remove();
}

4


In the for in that model of for each there is an iterator, which is a control mechanism of the items that is in the collection to go browsing the items. If you remove an item it gets complicated to keep keeping the iterator, it’s even possible that some implementation can get by with it, but not all of them are guaranteed that the iteration can continue smoothly, it may not even be possible to know more about the next items, You may not be able to identify more when you have finished the items, you may even run out prematurely. That kind of for exists to ensure that access is consistent. If you want risk and flexibility, you can still use the for ""and then it’s your problem to iterate on each item, it lets you do and take responsibility for problems.

And each language or implementation can have its own difficulties.

But this error may not occur. I did what you posted and did not give the error:

import java.util.*;

class Ideone {
    public static void main (String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        for (String i: list) {
            System.out.println("Antes => " + i);
            if (i == "b") list.remove(i);
            System.out.println("Depois => " + i);
        }
    }
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

This form is more guaranteed:

import java.util.*;

class Ideone {
    public static void main (String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        Iterator<String> i = list.iterator();
        while (i.hasNext()) {
            String nome = i.next();
            System.out.println("Antes => " + nome);
            i.remove();
            System.out.println("Depois => " + nome);
        }
    }
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

See an example where you can or can’t do exactly what you expect:

import java.util.*;

class Ideone {
    public static void main (String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        for (int i = 0; i < list.size(); i++) {
            System.out.println("Passo " + i + " Antes => " + list.get(i));
            list.remove(list.get(i));
            System.out.println("Passo " + i + " Depois => " + list.get(i));
        }
    }
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

After eliminating b he’s already going straight to c, was that what you wanted? It is not always expected, after all you are still in a step (the second) of the loop that was dealing with b. But it is different from the case above.

It makes a mistake:

import java.util.*;

class Ideone {
    public static void main (String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        for (String i: list) {
            System.out.println("Antes => " + i);
            list.remove(i);
            System.out.println("Depois => " + i);
        }
    }
}

It is because the iterator has already failed. Note that it does not give the error preventively, it gives when effectively lost.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.