The following code throws the concurrent modification exception
import java.util.*;
public class SampleTest
{
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("value1","a");
map.put("value2","b");
map.put("value3","c");
map.put("value4","d");
map.put("value5","e");
// sublists
List<LinkedHashMap<String, String>> subList = new ArrayList<>();
for(int i = 0; i<5; i++) {
subList.add(map);
}
List<List<LinkedHashMap<String, String>>> mainList = new LinkedList<>();
for(int i = 0; i<3; i++)
{
mainList.add(subList);
}
List<LinkedHashMap<String,String>> temp = mainList.get(mainList.size() - 1);
List<LinkedHashMap<String,String>> temp2 = mainList.get(mainList.size() - 2);
for(LinkedHashMap<String,String> map2 : temp) {
temp2.add(map); // Exception Thrown Here......
}
}
}
However i fixed the code by creating a new List and add the map and finally add the new list outside the loop in temp2
example,
List<LinkedHashMap<String,String>> pp = new ArrayList<>();
for(LinkedHashMap<String,String> map2 : temp) {
pp.add(map);
}
temp2.addAll(pp);
I would like to know in detail why the concurrent happens in the earlier code.
Thanks.
This code:
List<List<LinkedHashMap<String, String>>> mainList = new LinkedList<>();
for(int i = 0; i<3; i++)
{
mainList.add(subList);
}
Is adding subList
three times to mainList
. When I say "three times" I mean the code is literally adding the same instance three times. You could modify the element at any valid index of mainList
and you'd be modifying all the other elements because they're the same instance. See this question; it may help with this concept.
As a consequence, this code:
List<LinkedHashMap<String,String>> temp = mainList.get(mainList.size() - 1);
List<LinkedHashMap<String,String>> temp2 = mainList.get(mainList.size() - 2);
Grabs the same List
from two different indices and assigns it to two different variables. In other words, temp == temp2
(reference equality) is true
.
You then iterate the List
using the temp
variable while at the same time you are adding elements to the List
using the temp2
variable:
for(LinkedHashMap<String,String> map2 : temp) {
temp2.add(map); // Exception Thrown Here......
}
But again, temp
and temp2
refer to the same List
. Your code is basically doing the following:
List<Object> list = ...; // create new list and fill it
Object someObj = new Object();
for (Object obj : list) { // iterating list
list.add(someObj); // modifying list while it's being iterated
}
End result is you're iterating the List
while attempting to modify it at the same time. This is not allowed by LinkedList
(or really any of the standard implementations of Collection
). From the documentation:
The iterators returned by this class's
iterator
andlistIterator
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 ownremove
oradd
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.
If you aren't aware, the for-each loop internally uses an Iterator
when the target of the loop is an Iterable
.