Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration?

JavaListConcurrentmodification

Java Problem Overview


@Test
public void testListCur(){
	List<String> li=new ArrayList<String>();
	for(int i=0;i<10;i++){
		li.add("str"+i);
	}
	
	for(String st:li){
		if(st.equalsIgnoreCase("str3"))
			li.remove("str3");
	}
	System.out.println(li);
}

When I run this code,I will throw a ConcurrentModificationException.

It looks as though when I remove the specified element from the list, the list does not know its size have been changed.

I'm wondering if this is a common problem with collections and removing elements?

Java Solutions


Solution 1 - Java

I believe this is the purpose behind the Iterator.remove() method, to be able to remove an element from the collection while iterating.

For example:

Iterator<String> iter = li.iterator();
while(iter.hasNext()){
    if(iter.next().equalsIgnoreCase("str3"))
        iter.remove();
}

Solution 2 - Java

The Java 8 way to remove it from the List without Iterator is:

li.removeIf(<predicate>)

i.e.

List<String> li = new ArrayList<String>();
// ...
li.removeIf(st -> !st.equalsIgnoreCase("str3"));

Solution 3 - Java

> Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will thow this exception

Taken from http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html

Solution 4 - Java

yes people run into it -- the problem is you can't modify the list while iterating over it. I have used 2 alternatives in the past:

  1. You can keep track of the indexes of the items you want to remove, and then remove them after you are done iterating.
  2. Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.

those options assume you have to iterate over the list to find the elements to remove -- useful in cases where the list elements are complex objects with properties you might test on.

In your particular case, you dont even need to iterate, as you can just use removeAll. Look at the API here. There are also nifty methods like retainAll that discard everything that is not in the argument. You can use remove/retain-like methods whenever the objects in the list implement equals and hashcode properly. If you cannot rely on equals/hashcode to identify equality between instances in your app, you will have to do the removal yourself....

Solution 5 - Java

Try this (Java 8):

list.removeIf(condition);

Solution 6 - Java

You could make a copy of list you want to remove element from, directly in for-each loop. For me, that is the simpliest way. Something like this:

for (String stringIter : new ArrayList<String>(myList)) {
    myList.remove(itemToRemove);
}

Hope that will help you..

Solution 7 - Java

I think it is worth mentioning the Java 8 version

@Test
public void testListCur() {
    List<String> li = new ArrayList<String>();
    for (int i = 0; i < 10; i++) {
        li.add("str" + i);
    }

    li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList());

    System.out.println(li);
}

Solution 8 - Java

ArrayList has field modCount - count of collection modifications

When you invoke method iterator() creates new object Itr. It has field expectedModCount. expectedModCount field initialize by modCount value. When you invoke

li.remove("str3");

modCount increments. When do you try access to li via iterator checks that expectedModCount == modCount

and if it is false throws ConcurrentModificationException

Hence if you get iterator and after collection modified - iterator is considered not valid and you cannot use it.

Solution 9 - Java

I think that best answer is from bigdev.de, but i would like to add something to it(like if the item is removed from a list, maybe you would like to log that somewhere or something):

List<String> list = new ArrayList<>();

list.removeIf(a -> {
                boolean condition = a.equalsIgnoreCase("some condition");
                if(condition)
                    logger.info("Item removed from the list: " + a);
                return condition;
  });

Solution 10 - Java

I got this problem and I think the easier way is the same with the second way that hvgotcodes gave.

> Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.

@Test
public void testListCur(){
    List<String> li=new ArrayList<String>();
    for(int i=0;i<10;i++){
        li.add("str"+i);
    }
    List<String> finalLi = new ArrayList<String>();
    for(String st:li){
        if(st.equalsIgnoreCase("str3")){
            // Do nothing
        } else {
            finalLi.add(st);
        }
    }
    System.out.println(finalLi);
}

Solution 11 - Java

I looped a different way...

public void testListCur(){
	List<String> li=new ArrayList<String>();
	for(int i=0;i<10;i++){
		li.add("str"+i);
	}

    for(int i=0; i<li.size(); i++)
        if(li.get(i).equalsIgnoreCase("str3"))
            li.remove(i--);

	System.out.println(li);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhguserView Question on Stackoverflow
Solution 1 - JavaPaul BlessingView Answer on Stackoverflow
Solution 2 - Javabigdev.deView Answer on Stackoverflow
Solution 3 - JavaSerhiyView Answer on Stackoverflow
Solution 4 - JavahvgotcodesView Answer on Stackoverflow
Solution 5 - JavaTaras MelnykView Answer on Stackoverflow
Solution 6 - JavastakahopView Answer on Stackoverflow
Solution 7 - JavagdogaruView Answer on Stackoverflow
Solution 8 - JavagstackoverflowView Answer on Stackoverflow
Solution 9 - JavarpajazitiView Answer on Stackoverflow
Solution 10 - JavaEnvilView Answer on Stackoverflow
Solution 11 - JavaMark MeyersView Answer on Stackoverflow