2
public class Alpha {

    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<String>();

        al.add("a");
        al.add("b");
        al.add("c");
        al.add("d");
        al.add("e");


        Iterator<String> itr = al.listIterator();
        while(itr.hasNext()){
            al.remove("d"); // Throws a Concurrent Modification @ this line
            if(itr.next().equals("d")){
                //itr.remove();
                al.remove("d"); // No error on this line
            }

        }
        System.out.println(al);

    }

}

In other words, if "al.remove("d") is placed inside the if construct there is no ConcurrentModificationException thrown, where as the same line of code, if placed outside of the if -Construct throws an exception. Kindly explain!

7 Answers 7

2

It's because when you fetch next element using itr.next(), it will check for modification and check whether the size of collection has been changed or not. And at that time if (modCount != expectedModCount) condition will become true. While hasNext() method only return true or false, based on current cursor point.

While if you do like, itr.next() and then call remove on the list, then it will update the expectedModCount variable also. Check remove method of Arraylist iterator.

0

I have added a line (line 13) and some comment line numbers (line 18, line 19 & line 21).

Now, ConcurrentModidificationexception is not thrown at line 18, but it is thrown at line 19. But yeah it is thrown due to execution of line 18.

Also, I believe that you are using the code at lines 18 & 21 one at a time. They do not occur simultaneously in your code.

import java.util.*;

public class HelloWorld{

public static void main(String []args){
    ArrayList<String> al = new ArrayList<String>();

    al.add("a");
    al.add("b");
    al.add("c");
    al.add("d");
    al.add("e");
    al.add("f"); // line 13


    Iterator<String> itr = al.listIterator();
    while(itr.hasNext()){
        al.remove("d"); // line 18
        if(itr.next().equals("d")){  // line 19
            //itr.remove();
            al.remove("d"); // line 21
        }

    }
    System.out.println(al);
}
}

Lets comment line 13. So this is basically your code with some extra comments.

If we check the implementation of next() of iterator we come to know that it checks for any modification (and thereby throwing the CoMo) at the very beginning. After that it just returns the element.

So if we remove the element from the list without using the iterator at line 18, this gets detected at following next() call. But if you remove the element (at line 21; line 18 is commented by now) after next() method, CoMo will be detected only at the subsequent next(). What happens in your case is that we run out of element after printing 'e'. So we never executed subsequent next(), and didn't get the exception.

Now, if we uncomment the line 13 (which adds a new element), then we will get ConcurrentModidificationexception at line 19, i.e. when next next() is executed. This proves that we will get the CoMo Exception, it just that we will get it after one more iteration.

0
0

duplicate of: Iterating through a list, avoiding ConcurrentModificationException when removing in loop Removing items from a collection in java while iterating over it

simply u can not remove an element in iteration.

0

See how ArrayList iterator is implemented :

public void remove() {
if (lastRet < 0)
    throw new IllegalStateException();
checkForComodification();

try {
    ArrayList.this.remove(lastRet);
    cursor = lastRet;
    lastRet = -1;
    expectedModCount = modCount;
 } catch (IndexOutOfBoundsException ex) {
    throw new ConcurrentModificationException();
 }
}

So it checks for concurrent modifications, removes element using public ArrayList remove method, and increments counter of list modifications so ConcurrentModificationException won't be thrown at next iteration.

0

Its like you are modifying the file(here ArrayList) which is currently using by someone else(here iteration loop).

0
while(itr.hasNext()){

            if(itr.next().equals("d"))
            {
                //itr.remove();
                al.remove("d"); // No error on this line
            }

        }
        System.out.println(al);

Use this lines of code. Hope this will help

0

As @VimalBera pointed out in an earlier answer: you will have to fetch the next element using itr.next() before you can invoke remove on the List.

But, there are some alternative approaches that I find more suitable for this use case. The first is simply to use the iterator when removing elements:

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

    for (Iterator<String> itr = al.listIterator(); itr.hasNext(); ) {
        String s = itr.next();
        if ("d".equals(s)) {
            itr.remove();
        }
    }
    System.out.println(al);
}

Note that a for-loop is used instead of a while-loop. This reduces the scope of the iterator to the loop itself (which is good, always try to keep the scope as narrow as possible).

Another approach is to use the Java 8 Streams and especially the filter method. However, this creates a brand new list and does not really modify the underlying list but it offers a really nice programming model.

public static void main(String[] args) {
    List<String> al = Arrays.asList("a", "b", "c", "d", "e");
    List<String> filtered = al.stream()
            .filter(s -> !s.equals("d"))
            .collect(Collectors.toList());
    System.out.println(filtered);
}

Using this approach you obviously get the extra overhead of a new list but instead you gain that you can treat your list as immutable which will work beautifully in a multi-threaded environment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.