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

@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 seems that when I remove the specified item from the list, the list does not know that its size has been changed.

I am wondering if this is a common problem with collections and deleting items?

+59
java list concurrentmodification
Feb 25 '11 at 2:40
source share
11 answers

I believe this is the purpose of the Iterator.remove () method to be able to remove an item from the collection during iteration.

For example:

 Iterator<String> iter = li.iterator(); while(iter.hasNext()){ if(iter.next().equalsIgnoreCase("str3")) iter.remove(); } 
+86
Feb 25 '11 at 2:52
source share

Java 8 way to remove it from a list without an iterator:

 li.removeIf(<predicate>) 

those.

 List<String> li = new ArrayList<String>(); // ... li.removeIf(st -> !st.equalsIgnoreCase("str3")); 
+21
Nov 09 '14 at 18:06
source share

Note that this exception does not always indicate that the object was simultaneously modified by another thread. If one thread throws a sequence of method calls that violate the contract of the object, the object may throw this exception. For example, if a thread modifies a collection directly when iterating through a collection with a fast iterator, the iterator will throw this exception

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

+18
Feb 25 '11 at 2:45
source share

yes people are faced with this - the problem is that you cannot modify the list during iteration over it. I have used 2 alternatives in the past:

  • You can track the indices of the elements you want to delete, and then delete them after the iteration is complete.
  • Or you can copy all the ones you want to save to the new list as you repeat, and then discard the old list when you're done.

these options suggest that you need to iterate over the list to find the items to be deleted - useful in cases where the list items are complex objects with properties that you can check.

In your particular case, you donโ€™t even need to iterate over, as you can just use removeAll. Take a look at the API here . There are also great methods, such as keepAll, that drop everything that is not in the argument. You can use remove / ret-like methods when the objects in the list implement equal and hashcode correctly. If you cannot rely on equals / hashcode to identify equality between instances in your application, you will have to do the deletion yourself ...

+6
Feb 25 '11 at 2:44
source share

I think it is worth mentioning the version of Java 8

 @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); } 
+2
Apr 18 '14 at 17:26
source share

You can make a copy of the list from which you want to remove the item, right in the for-each loop. This is the easiest way for me. Something like that:

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

Hope this helps you.

+2
Jun 14 '17 at 13:40
source share

Try this (Java 8):

 list.removeIf(condition); 
+2
Nov 01 '17 at 13:59 on
source share

I had this problem, and I think the simpler way is the same with the second way hvgotcodes gave.

Or you can copy all the ones you want to save to the new list when you iterate, and then discard the old list when it's 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); } 
+1
Dec 05 '12 at 6:45
source share

ArrayList has a modCount field - the number of modifications to the collection.

When the iterator() method is called, a new Itr object is Itr . It has the expectedModCount field. expectedModCount initialized with the value of modCount . When you call

 li.remove("str3"); 

modCount increasing. When you try to access li through an iterator, it checks that expectedModCount == modCount

and if these are false throws ConcurrentModificationException

Therefore, if you receive an iterator even after changing the collection, the iterator is considered invalid and you cannot use it.

+1
Mar 11 '14 at 18:39
source share

I got stuck in 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); } 
0
Feb 15 '17 at 3:32
source share

I think the best answer is from bigdev.de, but I would like to add something to it (for example, if an item is removed from the list, maybe you would like to register it somewhere or something else):

 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; }); 
0
Jul 05 '17 at 12:52 on
source share



All Articles