I've been trying to take a sub list of a list, reverse it, and place the reversed list back into the starting position. For example, say we have the list [1, 2, 3, 4, 5, 6]
, then reversing from index 2 to index 4 would give [1, 2, 5, 4, 3, 6]
.
I've written some code for this, however it gives a ConcurrentModificationException
every time (unless startIndex == endIndex). A minimum reproducible example is provided below:
int startIndex = 2;
int endIndex = 4;
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
List<Integer> toReverse = list.subList(startIndex, endIndex+1);
Collections.reverse(toReverse);
list.removeAll(toReverse);
list.addAll(startIndex, toReverse);
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(Unknown Source)
at java.util.ArrayList$SubList.size(Unknown Source) at
java.util.AbstractCollection.toArray(Unknown Source) at
java.util.ArrayList.addAll(Unknown Source) at
test.ConcurrentExample.main(ConcurrentExample.java:64)
The actual line the error refers to is list.addAll(startIndex, toReverse);
.
I'm not sure what the issue is as nothing appears to be getting changed while being iterated over. If anyone could explain why this is happening and/or how to fix it, that would be greatly appreciated.
List.subList returns a live view of the list between the specified elements, not a copy of those elements (see documentation), therefore adding to the original list will also modify the sublist, which will lead to ConcurrentModificationException
(since what is being added and to what you add to also are modified at the same time).
list.subList(startIndex, endIndex+1)
You can fix a code by copying the list, like
List<Integer> toReverse = new ArrayList<>(list.subList(startIndex, endIndex+1));
from the documentation of ArrayList.subList :
The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa
So when you try to add items at the index of the subList 'view', it creates concurrent modification.
Issue lies here at ArrayList#checkForComodification
private void checkForComodification() {
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
}
}
However in this particular case you don't need to manually re-add reversed sublist, since the reversion is performed on the original list. So all you need is just to drop
list.removeAll(...);
list.addAll(...);
and leave only this code:
List<Integer> toReverse = list.subList(startIndex, endIndex+1);
Collections.reverse(toReverse);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With