我想合并具有相同名称的节点,并将它们的子节点添加到一起。 但是我得到了一个java.util.ConcurrentModificationException异常:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at test.Test.mergeNode(Test.java:60)
at test.Test.main(Test.java:43)
以下是来源。有人可以提供任何提示吗?任何建议都会受到欢迎。
public class Test {
public static void main(String[] args) throws Exception {
TreeLayoutNode root = new TreeLayoutNode();
root.setName("Production");
TreeLayoutNode node1 = new TreeLayoutNode();
node1.setName("node1");
TreeLayoutNode node2 = new TreeLayoutNode();
node2.setName("node1");
TreeLayoutNode child1 = new TreeLayoutNode();
child1.setName("child1");
TreeLayoutNode child2 = new TreeLayoutNode();
child2.setName("child2");
TreeLayoutNode child3 = new TreeLayoutNode();
child3.setName("child3");
root.addChildNode(node1);
root.addChildNode(node2);
node1.addChildNode(child1);
node1.addChildNode(child2);
node2.addChildNode(child1);
node2.addChildNode(child3);
HashMap<String, TreeLayoutNode> nodeMap = Maps.newHashMap();
mergeNode(root, nodeMap);
}
/**
*
* @param node
*/
private static void mergeNode(TreeLayoutNode node, HashMap<String, TreeLayoutNode> nodeMap) {
List<TreeLayoutNode> children = node.getChildren();
if(CollectionUtils.isEmpty(children)){
return;
}
Iterator<TreeLayoutNode> it = children.iterator();
while(it.hasNext()){
TreeLayoutNode child = it.next();
if(nodeMap.containsKey(child.getName())){
TreeLayoutNode duplicate = nodeMap.get(child.getName());
List<TreeLayoutNode> childrenOfChild = child.getChildren();
if(CollectionUtils.isNotEmpty(childrenOfChild)){
for(TreeLayoutNode single: childrenOfChild){
duplicate.addChildNode(single);
}
node.removeChildNode(child);
mergeNode(duplicate, nodeMap);
}
}else{
nodeMap.put(child.getName(), child);
}
}
}
}
public class TreeLayoutNode {
private String name;
private String parent;
private Long capacity;
private List<Proportion> proportions;
private List<TreeLayoutNode> children;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public Long getCapacity() {
return capacity;
}
public void setCapacity(Long capacity) {
this.capacity = capacity;
}
public List<Proportion> getProportions() {
return proportions;
}
public void setProportions(List<Proportion> proportions) {
this.proportions = proportions;
}
public List<TreeLayoutNode> getChildren() {
return children;
}
public void setChildren(List<TreeLayoutNode> children) {
this.children = children;
}
public void addChildNode(TreeLayoutNode child) {
if (children == null) {
children = Lists.newArrayList();
}
child.setParent(this.getName());
children.add(child);
}
public void removeChildNode(TreeLayoutNode child){
children.remove(child);
}
public void addProportion(Proportion proportion) {
if (proportions == null) {
proportions = Lists.newArrayList();
}
proportions.add(proportion);
}
public int hashCode() {
return name == null ? 0: name.hashCode();
}
public boolean equals(Object o) {
if (o instanceof TreeLayoutNode) {
TreeLayoutNode target = (TreeLayoutNode) o;
if (this.name == null) {
return target.getName() == null;
} else {
return this.name.equals(target.getName());
}
} else {
return false;
}
}
}
答案 0 :(得分:2)
Iterator<TreeLayoutNode> it = children.iterator();
while(it.hasNext()){
TreeLayoutNode child = it.next();
if(nodeMap.containsKey(child.getName())){
TreeLayoutNode duplicate = nodeMap.get(child.getName());
List<TreeLayoutNode> childrenOfChild = child.getChildren();
if(CollectionUtils.isNotEmpty(childrenOfChild)){
for(TreeLayoutNode single: childrenOfChild){
duplicate.addChildNode(single);
}
node.removeChildNode(child);
mergeNode(duplicate, nodeMap);
}
}else{
nodeMap.put(child.getName(), child);
}
}
此循环是代码中的问题。使用Iterator时,无法修改基础Collection。在这种情况下,你正在迭代“孩子们”。在此循环中,当您调用“node.removeChildNode(child)&#39;”时,您将从基础列表中删除项目。
解决方案是克隆孩子们的生活。在迭代之前列出它。
List< TreeLayoutNode > children = node.getChildren().clone();
这意味着您不再迭代稍后在方法中编辑的列表。
您还可以创建另一个List来存储子节点,在迭代完毕后将其删除。
List< TreeLayoutNode > removedChildren = new LinkedList< >();
// Iterate over the elements, adding children to be removed to removedChildren
for( TreeLayoutNode child : removedChildren ) {
node.removeChildNode( child );
}
最后你可以使用&#39; it.remove()&#39;从基础Collection中删除元素。该方法具有破坏封装的缺点。
// node.removeChildNode( child )
it.remove();