Search code examples
java-8jsoup

ConcurrentModificationException in Java Stream but not in for loop with counter


I am removing comment nodes with jsoup and found something I do not understand. This code works:
Example 1:

private static void removeComments(Node node) {
    for (int i = 0; i < node.childNodes().size();) {
        Node child = node.childNode(i);
        if (child.nodeName().equals("#comment"))
            child.remove();
        else {
            removeComments(child);
            i++;
        }
    }

But this code throws an ConcurrentModificationException:
Example 2

private static void removeComments(Node node) {
    node.childNodes()
            .forEach(n -> {
                if (n.nodeName().equals("#comment")) {
                    n.remove();
                } else {
                    removeComments(n);
                }
            });
}

I try to write short, easy to understand code, ternary operator not supporting two void returns already destroyed my "oneline" approach. What limitation did I hit with that strange behaviour?


Solution

  • ConcurrentModificationException occurs when you modify the list (by adding or removing elements) while traversing a list with an Iterator.

    You can't modify a List in a for/each loop, which is syntactic sugar around the Iterator as an implementation detail. You can only safely call .remove() when using the Iterator directly.

    Calling .remove() inside the for/each loop modifies the contents, and the Iterator that is used behind the scenes sees this and throws this exception.

    Read about How to Avoid ConcurrentModificationException when using an Iterator.