이름이 같은 노드를 병합하고 자식을 함께 추가하고 싶습니다. 하지만 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;
}
}
}
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를 사용하는 경우 기본 컬렉션을 수정할 수 없습니다. 이 경우이 루프에서 'children'을 반복하고 'node.removeChildNode (child)'를 호출 할 때 기본 목록에서 항목을 제거합니다.
해결책은 반복기 전에 '자식'목록을 복제하는 것입니다.
List< TreeLayoutNode > children = node.getChildren().clone();
즉, 나중에 메서드에서 편집중인 목록을 더 이상 반복하지 않습니다.
또한 반복 작업을 마친 후 제거 할 자식 노드를 저장할 다른 목록을 만들 수도 있습니다.
List< TreeLayoutNode > removedChildren = new LinkedList< >();
// Iterate over the elements, adding children to be removed to removedChildren
for( TreeLayoutNode child : removedChildren ) {
node.removeChildNode( child );
}
마지막으로 'it.remove ()'를 사용하여 기본 컬렉션에서 요소를 제거 할 수 있습니다. 이 방법은 캡슐화를 깨는 단점이 있습니다.
// node.removeChildNode( child )
it.remove();
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다