-4

why the following code won't throw ConcurrentModifyException just when remove 2

    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    for (String i: list) {
        if (i.equals("2")) {
            list.remove(i);
        }
    }
  • 1
    The question says "why the following code *won't* throw ConcurrentModifyException" – khelwood Sep 26 '21 at 07:17
  • (but in this case the loop is unnecessary: you could just have `list.remove("2");`) – khelwood Sep 26 '21 at 07:20
  • 4
    `ConcurrentModifyException` is documented to be thrown on a best-effort basis - do not rely on it. If it gets thrown, you *know* something is wrong. If it doesn't, it *might* be ok. – Hulk Sep 26 '21 at 07:20

1 Answers1

0

It’s on the border of being a bug.

As Hulk says in the comment, the documentation does not guarantee that a ConcurrentModificationException will be thrown when you modify the collection over which you are iterating. So they may reject a bug report. I still think that the implementation ought to be able to detect that you have modified the list before finishing iterating.

A guess at what happens is that a loop is set up to iterate as long is an internal index to the current element has not reached the length of the list. After you delete "2", the list holds [1, 3], that is, has length two. And the next index to iterate is index 2, that is the length of the list. So Java decides we’re done iterating and hence does not discover the modification.

As I said, in my world it ought to check for modification first, discover it and throw.

Even the following throws no exception on my Java 11. In every iteration it removes all elements except the first.

    for (String i: list) {
        list.subList(1, list.size()).clear();
    }

A simple different approach: For removing all the elements equal to 2 I would prefer the simple

    list.removeIf(i -> i.equals("2"));

(since Java 8).

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161