Java subList ConcurrentModificationException
最近在计算循环路径时使用了List的subList方法,在运行时会报java.util.ConcurrentModificationException
错误:
一、场景
大概场景如图所示,需要找出图中的循环路径,代码如下:
public static void main(String[] args) {
//next node map
Map<String, List<String>> map = new HashMap<>();
map.put("A", Arrays.asList(new String[]{"B"}));
map.put("B", Arrays.asList(new String[]{"C"}));
map.put("C", Arrays.asList(new String[]{"D"}));
map.put("D", Arrays.asList(new String[]{"B", "E"}));
map.put("E", Arrays.asList(new String[]{"C"}));
List<List<String>> cyclePaths = new ArrayList<>();
Stack<String> paths = new Stack<>();
//Start from the first node
findCyclePaths(map, cyclePaths, paths, "A");
System.out.println("The loop path is:");
System.out.println(cyclePaths);
}
private static void findCyclePaths(Map<String, List<String>> nextNodesMap, List<List<String>> cyclePaths, Stack<String> paths, String node){
List<String> nextNodes = nextNodesMap.get(node);
if(nextNodes == null || nextNodes.isEmpty()){
return;
}
for(String nextNode : nextNodes){
int index = paths.indexOf(nextNode);
if(index > -1){
//cycle
cyclePaths.add(paths.subList(index, paths.size()));
}else{
paths.add(nextNode);
findCyclePaths(nextNodesMap, cyclePaths, paths, nextNode);
paths.pop();
}
}
}
运行时在System.out.println(cyclePaths);
行报错:
The loop path is:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.SubList.checkForComodification(Unknown Source)
at java.util.SubList.listIterator(Unknown Source)
at java.util.AbstractList.listIterator(Unknown Source)
at java.util.SubList.iterator(Unknown Source)
at java.util.AbstractCollection.toString(Unknown Source)
at java.util.Collections$SynchronizedCollection.toString(Unknown Source)
at java.lang.String.valueOf(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at java.util.AbstractCollection.toString(Unknown Source)
at java.lang.String.valueOf(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at com.test.CyclePathTest.main(CyclePathTest.java:28)
二、解决方式
- 原因
由于subList方法返回的是fromIndex(包含)和toIndex(不包括)之间的列表视图,对返回的列表的更改将反映在原列表中;调试时可以看到第二次走到cyclePaths.add()
方法时会报com.sun.jdi.InvocationException occurred invoking method.
错误:
- 解决方式
将subList的结果创建一个新的List:
cyclePaths.add(paths.subList(index, paths.size()));
改为:
List<String> cyclePath = paths.subList(index, paths.size());
cyclePaths.add(new ArrayList<>(cyclePath));
再次运行,输出结果为:
The loop path is:
[[B, C, D], [C, D, E]]