How to avoid java.util.ConcurrentModificationException when iterating through and removing elements from an ArrayList

JavaArraylistForeach

Java Problem Overview


I have an ArrayList that I want to iterate over. While iterating over it I have to remove elements at the same time. Obviously this throws a java.util.ConcurrentModificationException.

What is the best practice to handle this problem? Should I clone the list first?

I remove the elements not in the loop itself but another part of the code.

My code looks like this:

public class Test() {
    private ArrayList<A> abc = new ArrayList<A>();
    
    public void doStuff() {
        for (A a : abc) 
        a.doSomething();
    }

    public void removeA(A a) {
        abc.remove(a);
    }
}

a.doSomething might call Test.removeA();

Java Solutions


Solution 1 - Java

Two options:

  • Create a list of values you wish to remove, adding to that list within the loop, then call originalList.removeAll(valuesToRemove) at the end
  • Use the remove() method on the iterator itself. Note that this means you can't use the enhanced for loop.

As an example of the second option, removing any strings with a length greater than 5 from a list:

List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String value = iterator.next();
    if (value.length() > 5) {
        iterator.remove();
    }
}

Solution 2 - Java

From the JavaDocs of the ArrayList

> The iterators returned by this class's iterator and listIterator > methods are fail-fast: if the list is structurally modified at any > time after the iterator is created, in any way except through the > iterator's own remove or add methods, the iterator will throw a > ConcurrentModificationException.

Solution 3 - Java

You are trying to remove value from list in advanced "for loop", which is not possible, even if you apply any trick (which you did in your code). Better way is to code iterator level as other advised here.

I wonder how people have not suggested traditional for loop approach.

for( int i = 0; i < lStringList.size(); i++ )
{
    String lValue = lStringList.get( i );
    if(lValue.equals("_Not_Required"))
    {
         lStringList.remove(lValue);
         i--; 
    }  
}

This works as well.

Solution 4 - Java

In Java 8 you can use the Collection Interface and do this by calling the removeIf method:

yourList.removeIf((A a) -> a.value == 2);

More information can be found here

Solution 5 - Java

You should really just iterate back the array in the traditional way

Every time you remove an element from the list, the elements after will be push forward. As long as you don't change elements other than the iterating one, the following code should work.

public class Test(){
    private ArrayList<A> abc = new ArrayList<A>();

    public void doStuff(){
        for(int i = (abc.size() - 1); i >= 0; i--) 
            abc.get(i).doSomething();
    }

    public void removeA(A a){
        abc.remove(a);
    }
}

Solution 6 - Java

While iterating the list, if you want to remove the element is possible. Let see below my examples,

ArrayList<String>  names = new ArrayList<String>();
		names.add("abc");
		names.add("def");
		names.add("ghi");
		names.add("xyz");

I have the above names of Array list. And i want to remove the "def" name from the above list,

for(String name : names){
	if(name.equals("def")){
		names.remove("def");
	}
}

The above code throws the ConcurrentModificationException exception because you are modifying the list while iterating.

So, to remove the "def" name from Arraylist by doing this way,

Iterator<String> itr = names.iterator();    		
while(itr.hasNext()){
	String name = itr.next();
	if(name.equals("def")){
		itr.remove();
	}
}

The above code, through iterator we can remove the "def" name from the Arraylist and try to print the array, you would be see the below output.

Output : [abc, ghi, xyz]

Solution 7 - Java

Do the loop in the normal way, the java.util.ConcurrentModificationException is an error related to the elements that are accessed.

So try:

for(int i = 0; i < list.size(); i++){
    lista.get(i).action();
}

Solution 8 - Java

Here is an example where I use a different list to add the objects for removal, then afterwards I use stream.foreach to remove elements from original list :

private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList();
...
private void removeOutdatedRowsElementsFromCustomerView()
{
	ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime());
	long diff;
	long diffSeconds;
	List<Object> objectsToRemove = new ArrayList<>();
	for(CustomerTableEntry item: customersTableViewItems) {
		diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime();
		diffSeconds = diff / 1000 % 60;
		if(diffSeconds > 10) {
			// Element has been idle for too long, meaning no communication, hence remove it
			System.out.printf("- Idle element [%s] - will be removed\n", item.getUserName());
			objectsToRemove.add(item);
		}
	}
	objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o));
}

Solution 9 - Java

One option is to modify the removeA method to this -

public void removeA(A a,Iterator<A> iterator) {
     iterator.remove(a);
     }

But this would mean your doSomething() should be able to pass the iterator to the remove method. Not a very good idea.

Can you do this in two step approach : In the first loop when you iterate over the list , instead of removing the selected elements , mark them as to be deleted. For this , you may simply copy these elements ( shallow copy ) into another List.

Then , once your iteration is done , simply do a removeAll from the first list all elements in the second list.

Solution 10 - Java

Instead of using For each loop, use normal for loop. for example,the below code removes all the element in the array list without giving java.util.ConcurrentModificationException. You can modify the condition in the loop according to your use case.

for(int i=0; i<abc.size(); i++)  {
       e.remove(i);
 }

Solution 11 - Java

In my case, the accepted answer is not working, It stops Exception but it causes some inconsistency in my List. The following solution is perfectly working for me.

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

for (String value: list) {
   if (value.length() > 5) { // your condition
       itemsToRemove.add(value);
   }
}
list.removeAll(itemsToRemove);

In this code, I have added the items to remove, in another list and then used list.removeAll method to remove all required items.

Solution 12 - Java

Do somehting simple like this:

for (Object object: (ArrayList<String>) list.clone()) {
    list.remove(object);
}

Solution 13 - Java

An alternative Java 8 solution using stream:

        theList = theList.stream()
            .filter(element -> !shouldBeRemoved(element))
            .collect(Collectors.toList());

In Java 7 you can use Guava instead:

        theList = FluentIterable.from(theList)
            .filter(new Predicate<String>() {
                @Override
                public boolean apply(String element) {
                    return !shouldBeRemoved(element);
                }
            })
            .toImmutableList();

Note, that the Guava example results in an immutable list which may or may not be what you want.

Solution 14 - Java

You can also use CopyOnWriteArrayList instead of an ArrayList. This is the latest recommended approach by from JDK 1.5 onwards.

Solution 15 - Java

for (A a : new ArrayList<>(abc)) {
    a.doSomething();
    abc.remove(a);
}

Solution 16 - Java

Sometimes old school is best. Just go for a simple for loop but make sure you start at the end of the list otherwise as you remove items you will get out of sync with your index.

List<String> list = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {
  if ("removeMe".equals(list.get(i))) {
    list.remove(i);
  }
}

Solution 17 - Java

"Should I clone the list first?"

That will be the easiest solution, remove from the clone, and copy the clone back after removal.

An example from my rummikub game:

SuppressWarnings("unchecked")
public void removeStones() {
  ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone();
  // remove the stones moved to the table
  for (Stone stone : stones) {
      if (stone.isOnTable()) {
         clone.remove(stone);
      }
  }
  stones = (ArrayList<Stone>) clone.clone();
  sortStones();
}

Solution 18 - Java

I arrive late I know but I answer this because I think this solution is simple and elegant:

List<String> listFixed = new ArrayList<String>();
List<String> dynamicList = new ArrayList<String>();
  	
public void fillingList() {
    listFixed.add("Andrea");
    listFixed.add("Susana");
    listFixed.add("Oscar");
    listFixed.add("Valeria");
    listFixed.add("Kathy");
    listFixed.add("Laura");
    listFixed.add("Ana");
    listFixed.add("Becker");
    listFixed.add("Abraham");
    dynamicList.addAll(listFixed);
}

public void updatingListFixed() {
    for (String newList : dynamicList) {
        if (!listFixed.contains(newList)) {
            listFixed.add(newList);
        }
    }
    
    //this is for add elements if you want eraser also 
    
    String removeRegister="";
    for (String fixedList : listFixed) {
        if (!dynamicList.contains(fixedList)) {
            removeResgister = fixedList;
        }
    }
    fixedList.remove(removeRegister);
}

All this is for updating from one list to other and you can make all from just one list and in method updating you check both list and can eraser or add elements betwen list. This means both list always it same size

Solution 19 - Java

Use Iterator instead of Array List

Have a set be converted to iterator with type match

And move to the next element and remove

Iterator<Insured> itr = insuredSet.iterator();
while (itr.hasNext()) {	
    itr.next();
    itr.remove();
}

Moving to the next is important here as it should take the index to remove element.

Solution 20 - Java

If your goal is to remove all elements from the list, you can iterate over each item, and then call:

list.clear()

Solution 21 - Java

What about of

import java.util.Collections;

List<A> abc = Collections.synchronizedList(new ArrayList<>());

Solution 22 - Java

ERROR

There was a mistake when I added to the same list from where I took elements:

fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
    for (i in this) {
        this.add(_fun(i))   <---   ERROR
    }
    return this   <--- ERROR
}

DECISION

Works great when adding to a new list:

fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
    val newList = mutableListOf<T>()   <---   DECISION
    for (i in this) {
        newList.add(_fun(i))   <---   DECISION
    }
    return newList   <---   DECISION
}

Solution 23 - Java

Just add a break after your ArrayList.remove(A) statement

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
QuestionanonView Question on Stackoverflow
Solution 1 - JavaJon SkeetView Answer on Stackoverflow
Solution 2 - JavaVarun AcharView Answer on Stackoverflow
Solution 3 - Javasuhas0sn07View Answer on Stackoverflow
Solution 4 - JavaggeoView Answer on Stackoverflow
Solution 5 - JavaMarcusView Answer on Stackoverflow
Solution 6 - JavaIndra KView Answer on Stackoverflow
Solution 7 - JavaTacilaView Answer on Stackoverflow
Solution 8 - JavaserupView Answer on Stackoverflow
Solution 9 - JavaBhaskarView Answer on Stackoverflow
Solution 10 - JavaShubham ChopraView Answer on Stackoverflow
Solution 11 - JavaAsad Ali ChoudhryView Answer on Stackoverflow
Solution 12 - JavaXMB5View Answer on Stackoverflow
Solution 13 - JavaZsolt SkyView Answer on Stackoverflow
Solution 14 - JavaPathikreetView Answer on Stackoverflow
Solution 15 - JavagachokaericView Answer on Stackoverflow
Solution 16 - JavaMatt StrainView Answer on Stackoverflow
Solution 17 - JavaArjen RodenhuisView Answer on Stackoverflow
Solution 18 - JavaBecquer Arguello FloresView Answer on Stackoverflow
Solution 19 - Javauser8009263View Answer on Stackoverflow
Solution 20 - JavaGiboltView Answer on Stackoverflow
Solution 21 - JavajoseluisbzView Answer on Stackoverflow
Solution 22 - JavaВладислав ШестернинView Answer on Stackoverflow
Solution 23 - JavaSebastian AltamiranoView Answer on Stackoverflow