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();
}
}
java.util.ConcurrentModificationException thrown when adding to List
The ConcurrentModificationException
is thrown when calling String value = it.next();
. But the actual culprit is list.add("6");
. You mustn't modify a Collection
while iterating over it directly. You are using it.remove();
which is fine, but not list.add("6");
.
While you can solve the problem with Stream
s, I will first offer a solution with Iterator
s, as this is a good first step for understanding the problem.
You need a ListIterator<String>
if you want to add and remove during iteration:
for (ListIterator<String> it = list.listIterator(); it.hasNext();){
String value = it.next();
if (value.equals("4")) {
it.remove();
it.add("6");
}
System.out.println("List Value: " + value);
}
This should do the trick!
A solution using Stream
s:
List<String> newList = list.stream()
.map(s -> s.equals("4") ? "6" : s)
.collect(Collectors.toList());
Here we create a Stream
from your List
. We map
all values to themselves, only "4"
gets mapped to "6"
and then we collect it back into a List
. But caution, newList
is immutable!
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();
}
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();
...
}
}
Concurrent Modification Exception : adding to an ArrayList
ConcurrentModificationException occurs when you modify the list (by adding or removing elements) while traversing a list with Iterator
.
Try
List<Element> thingsToBeAdd = new ArrayList<Element>();
for(Iterator<Element> it = mElements.iterator(); it.hasNext();) {
Element element = it.next();
if(...) {
//irrelevant stuff..
if(element.cFlag){
// mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
thingsToBeAdd.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
element.cFlag = false;
}
}
}
mElements.addAll(thingsToBeAdd );
Also you should consider enhanced for each loop as Jon suggested.
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
ConcurrentModificationException: Why does removing the null in List throw this Exception if it´s not the first variable
Well, in a best case scenario, the ConcurrentModificationException
should be thrown in any of the two cases. But it isn't (see the quote from the docs below).
If you use the for-each loop to iterate over an Iterable
, the Iterator
returned by the iterator()
method of the data structure will be used internally (the for-each loop is just syntactic sugar).
Now you shouldn't (structurally) modify an Iterable
that is being iterated after this Iterator
instance was created (it's illegal unless you use the Iterator
's remove()
method). This is what a concurrent modification is: There are two different perspectives on the same data structure. If it's modified from one perspective (list.remove(object)
), the other perspective (the Iterator) won't be aware of this.
It is not about the element being null
. The same happens if you change the code to remove the string:
ArrayList<Object> s = new ArrayList<>();
s.add("test");
s.add(null);
try {
System.out.println(s + "\n");
for (Object t : s) {
System.out.println(t);
if (t != null && t.equals("test")) {
s.remove(t);
System.out.println("ObjectRemoved = " + t + "\n");
}
}
System.out.println(s + "\n");
} catch (ConcurrentModificationException e) {
System.out.println(e);
} catch (Exception e) {
System.out.println(e);
}
Now the reason this behaviour differs in some scenarios is simply the following (from the Java SE 11 Docs for 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. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
ArrayList throwing `ConcurrentModificationException` when trying to run `.size()` method
The most glaring issue you have there is that you're using ArrayList.subList()
while you don't seem to understand what it really does:
Returns a view of the portion of this list ... The returned list is backed by this list.
What you're storing in messagesInFlight
is a view, not a copy. When you delete the first messages from messages
, you're in fact deleting the very messages you had in your messagesInFlight
right after subList()
call. So after the for
loop, there will be completely different messages, and the first n messages will be completely lost.
As to why you are getting the error you see - subList()
specifically allows non-structural changes to both sub-list and the original list (non-structural means replacing the elements, not adding or removing them), and the example in the documentation also showcases how the original list may be modified by modifying the sub-list. However, modifying the original list and then accessing it through the sub-list is not allowed and may result in ConcurrentModifcationException
, similarly to what happens when you change a list you're iterating through with an iterator.
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();
}
}
How to fix ConcurrentModificationException error when adding items during iteration
ListIterator has the add method, you can use it like this:
ListIterator<User> iterator = users.listIterator();
while(iterator.hasNext()) {
User u = iterator.next();
if(!user.getID().equals(u.getID())) {
iterator.add(user);
}
}
But to add a user only if it doesn't exist in the list you don't need an iterator. If you do it inside of the loop, you will add a user for each of the list's users that doesn't have the same id. But instead you need to check that the user's id is dirrenet from all users' ids and add the user only once.
If you are using Java 8, you could do something like this:
boolean userExists = users.stream().filter(u -> u.getID().equals(user.getID())).findFirst().isPresent();
if (!userExists) {
users.add(user);
}
Related Topics
How to Make This Jbutton Visible? When I Have Progressive Scan Background Jwindow()
Getting Unwanted Characters When Reading Command Output from Ssh Server Using Jsch
How to Find a Java Thread Running on Linux with Ps -Axl
Tomcat Doesn't Stop. How to Debug This
Couldn't Install Netbeans 11.3 with Java 14 Due to Error: "Unsupported Jvm Version"
Why This Javac: File Not Found Error
How to Check If a File Is Open by Another Process (Java/Linux)
Setting/Changing the Ctime or "Change Time" Attribute on a File
Obtaining the Thread Id for Java Threads in Linux
Could Not Reserve Enough Space for Object Heap to Start Jvm
Rjava Install Error "Java_Home Cannot Be Determined from the Registry"
Java File Locking Mechanism for File Based Process Communication
Commportidentifier.Getportidentifiers with Zero Ports on Linux
Runtime Exception Not Terminating the Programm
Load Native Libraries in an Eclipse Rcp Application on Linux