In Java, Can You Modify a List While Iterating Through It

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

change a list while iterating or using a for each loop

You can't iterate over a collection and modify it. You will always get a java.util.ConcurrentModificationException. First off all you need to use an iterator, to remove the item. Then you can use a second list to store the data you want to add.

Here you are an example:

LinkedList<String> linkedList = new LinkedList<String>();

linkedList.add("This");
linkedList.add("is");
linkedList.add("an");
linkedList.add("test");

LinkedList<String> temp = new LinkedList<String>();

for (Iterator<String> iterator = linkedList.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();

if(string.equals("an")) {
iterator.remove();

temp.add("a");
}
}

linkedList.addAll(temp);

You can call iterator.remove() to savely remove the current item from list.

Modify a list while it is being iterating

Fundamentally, you're modifying a list in one thread while iterating over it in another, and the list implementation you're using does not support that.

The ArrayList iterator implementation appears to only detect invalid modicifications on the call to next(), not on the call to hasNext(). So if you get into the last iteration of the loop before the remove() call, then you won't get an exception - hasNext() will just return false. On the other hand, if the remove() happens before the last call to next() (and if this is noticed on the other thread - the memory model comes into play here) then you'll get the exception. So for example, if you change your in-loop sleep to Thread.sleep(2500) then you'll get the exception at the start of the second iteration, because the remove() call will occur before it.

If you want to use a list in multiple threads and at least one of them is modifying it, you should use an implementation which supports that, such as CopyOnWriteArrayList.

How to modify elements of a list as I iterate through them in Kotlin ("Val cannot be reasigned")?

First of all, when iterating over a collection, we don't receive some kind of a pointer to the current item. item in your example is only a copy of the current item and modifying it would not affect the list. This is one reason why item is read-only - otherwise it would be misleading as developers would think they modified the list, but in fact they would not. In order to replace the current item we have to either use ListIterator.set() or access the item using its index.

Secondly, it would be tricky to add new items at the end while iterating over the same collection. It is much easier to just remember the number of 0 items and add 10 items after we finish iterating.

Solution using ListIterator.set():

fun listCalculator(myList: MutableList<Int>, number: Int) {
for (i in 0..number) {
var counter = 0
val iterator = myList.listIterator()
for (item in iterator) {
iterator.set(item - 1)

if (item == 1) {
counter++
}
}

repeat(counter) { myList += 10 }
}
}

Solution where we iterate over indices and access the current item manually:

fun listCalculator(myList: MutableList<Int>, number: Int) {
for (i in 0..number) {
var counter = 0
for (index in myList.indices) {
val item = --myList[index]

if (item == 0) {
counter++
}
}

repeat(counter) { myList += 10 }
}
}

Also note that the outer loop does not run number times, but number + 1 times. If you intended to execute it number times, then you have to use for (i in 0 until number) { ... } or just: repeat(number) { ... }

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.



Related Topics



Leave a reply



Submit