트리 구조에서 노드를 병합하는 동안 java.util.ConcurrentModificationException이 발생했습니다.

빈센트

이름이 같은 노드를 병합하고 자식을 함께 추가하고 싶습니다. 하지만 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;
        }
    }
}  
Smith_61
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] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관