How to avoid ConcurrentModificationException while removing elements from `ArrayList` while iterating it?
Use an Iterator
and call remove()
:
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
How to avoid java.util.ConcurrentModificationException when iterating through and removing elements from an ArrayList
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();
}
}
ConcurrentModificationException when removing item from a list
ConcurrentModificationException means:
- At point in time A, you make an iterator of some collection either by invoking its
.iterator()
method, or having afor (var x : collection) {}
call it for you. - At point in time B, you change the collection (and not via the iterator you made in A's
.remove()
method), for example by invokingremove
oradd
orclear
orretainAll
. - At point in time C, you so much at look funny at that iterator: You invoke any of its methods, or you have the for loop do it by hitting the
}
of its block.
What you need to do is decidedly nontrivial!
Think about it, given an initial list of [A, B, C, D, E]: you'd presumably want that forEachWithIndex
method to get run 5 times, regardless of what happens to the list in between: [0, A], [1, B], [2, C], [3, D], and [4, E]. So what should happen if, during the loop for [0, A]
, you remove C?
There's an argument to be made that the [2, C]
event shouldn't happen at all, and, in fact, that the remaining loops should be [1, B]
, [2, D]
, and [3, E]
. It's because this is so hard to answer that java solved the problem in the iterator()
API by simply not allowing you to do it!
Similar question comes up when you call .add("F")
during the loop for [0, A]
. Should the for loop run the lambda once with arguments [5, F]
, or not? An open question.
It's up to you to answer this question, and you should document this in excruciating detail. No matter which choice you make it'll be quite difficult!
I think the for loop should include the changes
This is incredibly complicated. Because imagine that the loop for C ends up removing A. That means that your list will first invoke the lambda with arguments [0, A]
, [1, B]
, and [2, C]
, and then, what's the next iteration going to look like? Presumably the only sane answer then is [2, D]
. To make this work you need to track all sorts of things - the list's loop code needs to be aware that deletions happened and that therefore it needs to 'down-adjust' (because you can't simply loop from 0 to 'list size', if you did that, the next iteration would be [3, E]
and you have skipped D entirely even though it is still in that list.
Make some coffee, dig in, find a whiteboard, sketch this out. Reserve a full day and be aware that the code will be many pages to deal with it all. Make a TON of test cases and describe in detail precisely what you expect to happen for all of these.
Hmm, okay, nevermind. Let's say it should iterate for all elements the original had no matter what changes
This is easier but inefficient. The fix is simple: First make a copy of the list. Then iterate the copy. The copy cannot change (you're the only one with a ref to it), so they can do whatever they want to the underlying list:
XList<T> copy = new XList<T>(this);
int counter = 0;
var iterator = copy.iterator();
while (iterator.hasNext()) consumer.accept(iterator.next(), counter++);
ConcurrentModificationException for ArrayList
You can't remove from list if you're browsing it with "for each" loop. You can use Iterator
. Replace:
for (DrugStrength aDrugStrength : aDrugStrengthList) {
if (!aDrugStrength.isValidDrugDescription()) {
aDrugStrengthList.remove(aDrugStrength);
}
}
With:
for (Iterator<DrugStrength> it = aDrugStrengthList.iterator(); it.hasNext(); ) {
DrugStrength aDrugStrength = it.next();
if (!aDrugStrength.isValidDrugDescription()) {
it.remove();
}
}
ConcurrentModificationException while trying to delete an item from ArrayList
You cannot call remove()
from inside a "for-each" loop (the for (item : collection)
structure). Doing so will throw that ConcurrentModificationException
.
If you want to loop and remove items while looping, you can use a traditional "for" loop:
for (int i = 0; i < itemStorico.size(); ++i) {
ItemModel itemModel2 = itemStorico.get(i);
if (...) {
itemStorico.remove(i);
...
}
}
However, this will introduce a subtle bug. Imagine you're looping over [a,b,c,d]
. If you are at index 1 and remove b
from the collection, everything will "slide over" and you'll have [a,c,d]
. When you next look at index 2, you'll have skipped over c
.
You can avoid the bug by manually decrementing the index when you remove, but it's a little gross.
...
itemStorico.remove(i);
--i;
...
You can also avoid the problem altogether by using the collection's iterator()
.
for (Iterator<ItemModel> iterator = itemStorico.iterator(); iterator.hasNext(); ) {
ItemModel itemModel2 = iterator.next();
if (...) {
iterator.remove();
...
}
}
java.util.ConcurrentModificationException when removing elements from arraylist even with iterators
If you are iterating over a collection
using an iterator
then you can only modify the collection
using iterator's mutator methods, if you try to modify the collection using collection's mutator methods (remove,set etc) then iterator
throws ConcurrentModificationException
, this is known as fail-fast property of iterators.
in your case instead of doing snaps.removeAt(index)
, you should do iterator.remove()
Please note that iterator.remove
removes the last element returned by the iterator. So in order to remove an element you have to call next()
method first. For example lets say you wanted to remove first element. to achieve this you will have to do the following.
iterator.next()
iterator.remove() // Removes the element returned by next
works if the items are less than 3 in the arraylist, but if items are
3 or more than 3 I get the same error
This is because, the ConcurrentModificationException
is thrown by next()
method, and because in case of 1 or 2 elements it only gets called once, that to before any modification, so you don't get any error. In above cases following steps are executed:
1. iterator.hasNext() // returns true
2. iterator.next() // works fine, since we have not modified collection yet
3. snaps.removeAt(index) // removes one element
4. iterator.hasNext() // returns false as there is only one element in list
5. iterator.next // this line is not executed and hence no error
How do I avoid ConcurrentModificationException in ArrayList ONLY when iterating?
The issue comes from the fact that masterList
is a reference to either contains
or doesNotContain
after a first split. When you iterate on masterList
, you actually also iterate at the same time on that other list.
So, then you add items to the lists:
if(i.contains(guessString)){
contains.add(i);
}else{
doesNotContain.add(i);
}
Here you do not only add items to contains
or doesNotContain
, but also potentially to masterList
, which leads to the conccurentException
.
To solve your issue, just make a copy of your lists, instead of : masterList = contains;
do a copy with: masterList = new ArrayList<>(contains);
And the same for doesNotContains
.
Another solution which comes to mind is to reset the two lists contains
and doesNotContains
for each split. Since you only use them in this method, and nowhere else, remove these two lists from your Class, and defines them as private variables inside splitFamilies
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
Iterator.remove()
is safe, you can use it like this:
List<String> list = new ArrayList<>();
// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
// Iterator<String> iterator = list.iterator();
// while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
// Remove the current element from the iterator and the list.
iterator.remove();
}
}
Note that Iterator.remove()
is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Source: docs.oracle > The Collection Interface
And similarly, if you have a ListIterator
and want to add items, you can use ListIterator#add
, for the same reason you can use Iterator#remove
— it's designed to allow it.
In your case you tried to remove from a list, but the same restriction applies if trying to put
into a Map
while iterating its content.
Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration?
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();
}
ConcurrentModificationException when removing an object from ArrayList
While iterating the Arraylist
, you are not allowed to remove any item. If you want to remove an item while iteration, you can add removed item into newly created ArrayList
say,. willBeRemovedList
after iteration completed you can remove all of them at a time.
Related Topics
Variable Is Accessed Within Inner Class. Needs to Be Declared Final
How to Scroll a Scrollview Programmatically in Android
Best Way to Compare Dates in Android
How to Execute Linux Commands on a Remote MAChine Using Java
Does Python Have an Equivalent to Java Class.Forname()
Convert Character to Ascii Numeric Value in Java
What Does Statement.Setfetchsize(Nsize) Method Really Do in SQL Server Jdbc Driver
How to Do a Junit Assert on a Message in a Logger
Handling MySQL Datetimes and Timestamps in Java
How to Understand Happens-Before Consistent
Webview and Cookies on Android
Setting Custom Actionbar Title from Fragment
Can't Make Jdbc Connection to MySQL (Using Java, Intellij, and Linux)