Remove item from a collection

2

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

for(String item: list) {
  list.remove(item);
}
    
asked by anonymous 06.11.2018 / 19:36

2 answers

3

No for in this model of for each there is an iterator, which is a control mechanism of the items that are in the collection to navigate the items. If you remove an item it is difficult to continue maintaining the iterator, it is even possible that some implementation can get along with this, but not all are guaranteed that the iteration can continue without problems, it may not even be possible to know what the next items are, you may not be able to identify more when items are over, you may even end items prematurely. This type of for exists to ensure that access is consistent. If you want the risk and flexibility, you can still use the for "gross" and there it is problem to iterate in each item, it lets you do and take responsibility for problems.

And every language or implementation can have its own difficulties.

But this error may not occur. I did what I 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);
        }
    }
}

See running on ideone . And no Coding Ground . Also put it in 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);
        }
    }
}

See running on ideone . And no Coding Ground . Also I placed GitHub for future reference .

See an example where you can or do not 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));
        }
    }
}

See running on ideone . And no Coding Ground . Also I placed GitHub for future reference .

After deleting b it goes straight to c , is this what you wanted? It is not always the expected, after all you are still in a step (the second) of the loop that was trying to b . But it is different from what happened in the cases above.

So that gives 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);
            list.remove(i);
            System.out.println("Depois => " + i);
        }
    }
}

It is because the iterator has already made an error. Note that it does not give the error preemptively, it gives when it is actually lost.

    
06.11.2018 / 20:11
3
  

Why is the ConcurrentModificationException exception thrown?

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

In other words, before "in fact" gives a problem, if there is any change in the collection, the trigger trigger is done.

To get around this, you can use Iterator .
Actually, for each uses Iterator underneath the wipes, but to be less verbose, it "hides" the whole code and you do not have to type everything all the time.

To solve the problem you can do something like:

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String item = iterator.next();
    iterator.remove();
}
    
06.11.2018 / 20:11