5

I wrote this example following a test ConcurrentModificationException concept:

public class Person
{
    String name;
    public Person(String name)
    {
        this.name = name;
    }
}

public static void main(String[] args)
{
    List<Person> l = new ArrayList<Person>();
    l.add(new Person("a"));
    l.add(new Person("b"));
    l.add(new Person("c"));

    int i  = 0;
    for(Person s : l)
    {
        if(s.name.equals("b"))
            l.remove(i);
        i++;
    }

    for(Person s : l)
        System.out.println(s.name);
}

When I executed the above main method, ConcurrentModificationException doesn't get thrown and the output console prints the following result:

a
c

By with my knowledge of this issue, when in a loop for list, when modifying the list,a ConcurrentModificationException exception should be thrown. But why in my sample does this not occur?

Laurentiu L.
  • 6,566
  • 1
  • 34
  • 60
Sam
  • 6,770
  • 7
  • 50
  • 91
  • 2
    There is no *guarantee* that structural modifications to the list will throw a `ConcurrentModificationException`. – aioobe Jun 16 '15 at 11:15
  • Likely because of implementation details of ArrayList. Have a read of https://stackoverflow.com/questions/18448671/how-to-avoid-concurrentmodificationexception-while-removing-elements-from-arr – Armand Jun 16 '15 at 11:17
  • 1
    Because your loop exits right after `remove`. You will get the exception if you add a 4th element after "c" or if you remove Person "a". – Marvin Jun 16 '15 at 11:17
  • @Marvin points out the behaviour. – Naman Gala Jun 16 '15 at 11:22

1 Answers1

1

There is no guarantee that structural modifications to the list will throw a ConcurrentModificationException.

From the documentation:

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

In this particular case, you're "lucky" (or "unlucky" depending on how you see it). The structural change goes unnoticed since the loop exists before another modification check is performed.

For a detailed explanation, refer to the answers in the dup:

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 1
    I'd hesitate to consider this as an answer... – Marco13 Jun 16 '15 at 11:18
  • @Marco13, what do you mean? Could you clarify? My answer shows that the behavior adheres to the contract. – aioobe Jun 16 '15 at 11:21
  • 1
    Yes, but it does not explain the "why" in any form. Admittedly, I would also have expected it to throw. For example, add one more person to the list, and then it throws. Why doesn't it for this particular setup? (I'm currently investigating this... a good question IMHO) – Marco13 Jun 16 '15 at 11:23
  • Updated my answer. (Note however, that a formal answer would require OP to also provide details on which runtime implementation is used, since without it one can only look at the contract (javadoc) and speculate about the implementation.) – aioobe Jun 16 '15 at 11:27
  • OK, this is indeed a duplicate, but I was about to post basically the same as http://stackoverflow.com/a/14674151/3182664 (Even though it refers to a particular implementation, the point that `hasNext` does not throw but may be implemented in a way that refers to the *current* size of the list is what I would consider as "the answer" here - just IMHO, no offense) – Marco13 Jun 16 '15 at 11:47
  • Ok, well feel free to edit the answer if you like (I've made it a community wiki). – aioobe Jun 16 '15 at 12:13