How to Modify a Collection While Iterating Using For-Each Loop Without Concurrentmodificationexception

How to modify a Collection while iterating using for-each loop without ConcurrentModificationException?

Use Iterator#remove.

This is the only safe way to modify a collection during iteration. For more information, see The Collection Interface tutorial.

If you also need the ability to add elements while iterating, use a ListIterator.

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.

How to avoid ConcurrentModificationException while iterating this collection?

This code cannot lead to ConcurrentModificationException because after you add an element you break the loop and dont use iterator anymore

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();
}

Concepts of modifying the element in collection while iterating?

Question1:- So can i say enhance for loop also uses the fail-fast iterator internally?Though when i execute below code it works fine

Yes, thats right. Have a look at the compiled code, with the javap command to verify this if you like.

My guess is that modification means here removal or addition not for updation of element inside collection for list interface while it also includes modification of element for set interface . Right? Atleast the programmes i tried it is the case with them.

Thats right, if you do emp1.setEmpId(2) or something similar, the iteration will not fail.

...it should throw the concurrent modification exception but it did not . Not sure why?

It only throws the exception if you modify the list. Keep in mind that the list contains references to objects. If you modify the objects, the references does not change, thus the list does not change.

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();
}
}

Why iterator.remove does not throw ConcurrentModificationException

ConcurrentModificationException is not thrown by Iterator.remove() because that is the permitted way to modify an collection while iterating. This is what the javadoc for Iterator says:

Removes from the underlying collection the last element returned by this iterator (optional operation). This method can be called only once per call to next(). The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.

If you change the collection being iterated any other way, then you are liable to get an exception, depending on the implementation of iterator, and the collection (or whatever) that you are iterating. (Some collection classes won't give you a ConcurrentModificationException: check the respective javadocs to see how they specify the behavior of their iterators)

You are also liable to get an exception if you have two iterators on the same collection, and you remove via one of them.


What iterator.remove does different from list.remove that iterator does not throw exception while list.remove does throw?

Reason #1. If you had a non-concurrent collection being updated simultaneously from two places on the same call stack, the behavior would break the design invariant for the iteration1. An iteration of a non-concurrent collection is guaranteed to see all of the elements in the collection exactly once. (By contrast, with concurrent collections these guarantees are relaxed.)

Reason #2. Non-concurrent collection types are not implemented to be thread-safe. Therefore, you could have race conditions and memory anomalies if the collection and iterator are used to update the collection by different threads. This is not strong reason because you will have these problems anyway. However, having the updates happening in two different ways makes the problem worse.


I am just talking about for-each loop and iterator loop. As far as I know for-each loop internally create iterator only.

That is correct. A for-each loop is really just syntactic sugar for a while loop using an iterator.

On the other hand, if you use a loop like this:

    for (int i = 0; i < list.size(); i++) {
if (...) {
list.remove(i);
}
}

you won't get ConcurrentModificationException, but you will need to adjust the index variable for the elements that you delete, and updates by another thread are liable to cause you to skip elements or visit them more than once2.


1 - To achieve "exactly once" iteration behavior, when you remove an element via the collection object, the iterator data structure would need to be updated to keep it in step with what has happened to the collection. This is not possible in the current implementations because they don't keep links to the outstanding iterators. And if they did, they would need to use Reference objects or risk memory leaks.

2 - Or even get an IndexOutOfBoundsException. And if the collection is not concurrent / properly synchronized, you can get worse problems.

In Java, can you modify a List while iterating through it?

There is nothing wrong with the idea of modifying an element inside a list while traversing it (don't modify the list itself, that's not recommended), but it can be better expressed like this:

for (int i = 0; i < letters.size(); i++) {
letters.set(i, "D");
}

At the end the whole list will have the letter "D" as its content. It's not a good idea to use an enhanced for loop in this case, you're not using the iteration variable for anything, and besides you can't modify the list's contents using the iteration variable.

Notice that the above snippet is not modifying the list's structure - meaning: no elements are added or removed and the lists' size remains constant. Simply replacing one element by another doesn't count as a structural modification. Here's the link to the documentation quoted by @ZouZou in the comments, it states that:

A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification



Related Topics



Leave a reply



Submit