0

below is my code snippet. The java docs on oracle says that only right way to remove list element while iterating is through iterator's remove method. But in the below code snippet i remove through list's remove method but i did not get any exception. Why is this so?

Using jdk 12 on netbeans

List<String> emps = new ArrayList<>();
emps.add("trump");
emps.add("angela");
emps.add("jinping");
emps.add("trudeau");

System.out.println(emps.size());

for (int i = 0; i < emps.size(); i++) {
    if ("trudeau".equalsIgnoreCase(emps.get(i))) {
        emps.remove(emps.get(i));
    }
}

System.out.println(emps.size());
deHaar
  • 17,687
  • 10
  • 38
  • 51
tin_tin
  • 478
  • 3
  • 10
  • 24

2 Answers2

3

You only get ConcurrentModificationExceptions when you iterate with the iterator (think for(String emp : emps)), not when you use int-based indexing.

  • by concurrentmodification exception i understand that while iterating one should not be able to modify the list. The sample code (though incorrect) i provided is able to modify the list. So what is the point of concurrentmodification exception? what is that authors are trying to convey – tin_tin Mar 20 '20 at 17:41
  • 1
    @tin_tin When you use a [for each](https://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work) you are using the iterator of the list to iterate over the list. If you change the list while doing so you will get the `ConcurrentModificationException`. If you just randomly pick one element from a list with the `get(...)` method, no one cares. It's like I'm holding a deck in my hand and dealing cards (iterating) and you pick a card directly from my hand changing the deck I'm holding (`ConcurrentModificationException`). I would go "dude, what the hell?". – Progman Mar 20 '20 at 19:26
2

The provided code does not cause a ConcurrentModificationException because it does not iterate over the List in a proper way.

for( var emp : emps )
{
    if( "trudeau".equalsIgnoreCase( emp ) ) 
    {
        emps.remove( emp );
    }
}

would give you the 'desired' result.

Or

for( var i = emps.iterator(); i.hasNext(); )
{
    var emp = i.next();
    if( "trudeau".equalsIgnoreCase( emp ) ) 
    {
        emps.remove( emp );
    }
}

has the same outcome.

What is meant in the JavaDoc is this:

for( var i = emps.iterator(); i.hasNext(); )
{
    var emp = i.next();
    if( "trudeau".equalsIgnoreCase( emp ) ) 
    {
        i.remove();
    }
}

Of course the provided code somehow iterates over the List, and it will not throw an exception, at least not a ConcurrentModificationException, but it is nonetheless problematic.

Assume the following list:

  1. trump
  2. angela
  3. jinping
  4. trudeau
  5. trudeau
  6. bush

For i == 3, you will remove the "trudeau" in line 4. Fine! And now the "trudeau" from line 5 is on line 4, but i had been increased to 4, pointing to "bush" …

You can try this:

for( int i = 0; i < emps.size(); ++i ) 
{
    while( (i < emps.size()) && "trudeau".equalsIgnoreCase( emps.get( i ) ) ) 
    {
        emps.remove(emps.get(i));
    }
}
tquadrat
  • 3,033
  • 1
  • 16
  • 29
  • you said that i did not iterate the list in correct way? does that mean for each loop and iterator are correct way to iterate over list. I have been iterating the list the way i wrote without any issues.. please correct any error on my part. – tin_tin Mar 20 '20 at 17:39
  • by concurrentmodification exception i understand that while iterating one should not be able to modify the list. The sample code (though incorrect) i provided is able to modify the list. So what is the point of concurrentmodification exception? what is that authors are trying to convey. – tin_tin Mar 20 '20 at 17:41
  • @tin_tin: "Not *proper* way" in the meaning that your way (iterating utilizing the index) does not cause a CME. *Technically* your approach is "iterating", but when the authors of Java used that term, they thought more about the first two approaches in my answer. – tquadrat Mar 20 '20 at 21:21
  • 1
    @tin_tin: And my sample at the end shows that your code does show that modifying a list while iterating it is possible without a CME, but also that the results are unpredictable/completely relying on the contents of the list. When you read the documentation for CME, you will find the term "fail-fast behaviour" there: it means that a CME is thrown to give you the chance to detect problems like those I described an the end of my answer, and to detect them *fast*. – tquadrat Mar 20 '20 at 21:28
  • precise..to the point answer. your answer cleared many doubts and misconception.. – tin_tin Mar 21 '20 at 05:11