Using Java, I have a list to be checked and in case one of the sublists retrieved through a loop meets some condition, it must be replaced on the fly, since in the next loop I must repeat the algorithm on the changed list. The sublist to be replaced and that to add can have different lengths of course.
I am using a ListIterator since adding and removing using normal List methods can't guarantee the result. But even here, a ConcurrentModificationException is thrown at the beginning of the first for loop (at its second iteration) inside the main for loop, and I can't really think of another way to perform the algorithm.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
public class Dummy {
public static void main(String[] args) {
List<String> nodes = new ArrayList<>(Arrays.asList(
"1", "2", "3", "4", "5", "6", "7"));
ListIterator<String> nodesIterator = nodes.listIterator();
while (nodesIterator.hasNext()) {
nodesIterator.next();
List<String> nodesToCheck = nodes.subList(nodesIterator
.previousIndex(),
nodesIterator.previousIndex() + 3);
if (nodesToCheck.equals(Arrays.asList("3", "4", "5"))) {
List<String> nodesToReplace = new ArrayList<String>(
Arrays.asList("11", "11", "00", "11"));
for (String n : nodesToCheck) {
//ConcurrentModificationException thrown here at
// beginning of second iteration
nodesIterator.remove();
nodesIterator.next();
}
for (String n : nodesToReplace) {
nodesIterator.add(n);
}
}
}
}
}
Any help is extremely appreciated, thanks ;)
You're modifying the initial nodes list so it's natural that an exception is thrown. You should iterate over a copy of the nodes list.
Here is a runnable example that reproduces the problem (I wrote before OP was edited):
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
public class Main {
public static void main(String[] args) {
int number = 2;
List<String> nodes = new ArrayList<>(Arrays.asList("Hello",
"World!", "How", "Are", "You"));
ListIterator<String> nodesIterator = nodes.listIterator();
while (nodesIterator.hasNext()) {
nodesIterator.next();
int fromIndex = nodesIterator.previousIndex();
List<String> nodesToCheck = nodes.subList(fromIndex,fromIndex + number);
if (nodesToCheck.contains("Hello")) {
for (String n : nodesToCheck) { //ConcurrentModificationException
// thrown here at beginning of second iteration
nodesIterator.remove();
nodesIterator.next();
}
List<String> nodesToReplace = new ArrayList<>(
Arrays.asList("replace"));
for (String n : nodesToReplace) {
nodesIterator.add(n);
}
}
}
}
}
A quick and dirty way of patching this (which can be necessary in more complex designs) is:
public class Main {
public static void main(String[] args) {
int number = 2;
List<String> nodes = new ArrayList<>(Arrays.asList("Hello", "World!",
"How", "Are", "You"));
boolean change = true;
while (change) {
List<String> copy = new ArrayList<>(nodes);
ListIterator<String> nodesIterator = copy.listIterator();
while (nodesIterator.hasNext()) {
nodesIterator.next();
int fromIndex = nodesIterator.previousIndex();
List<String> nodesToCheck = nodes.subList(fromIndex, Math.min
(fromIndex + number, nodes.size()));
if ((nodesToCheck.equals(Arrays.asList("How", "Are")) ||
nodesToCheck.equals(Arrays.asList("Hello", "World!")))) {
for (String n : nodesToCheck) {
//ConcurrentModificationException thrown here
// at beginning of second iteration
nodesIterator.remove();
if (nodesIterator.hasNext()) {
nodesIterator.next();
}
}
nodesIterator.previous();
List<String> nodesToReplace = new ArrayList<>(Arrays.asList
("replace"));
for (String n : nodesToReplace) {
nodesIterator.add(n);
}
nodes = copy;
change = true;
break;
} else change = false;
}
}
System.out.println(Arrays.toString(nodes.toArray()));
}
}
Although it can be further simplified. That's a general programming approach to such problems however - while there is something changing rerun through the collection and modify till there is no change.