0

我已经阅读了一些关于ConcurrentModificationExceptionstackflow 的内容,并且我的实际更新似乎不是问题,这可能是我的设计中的问题,或者我需要一种我还没有学过的技术。

示例情况:我的迭代器沿着位置标记运行。然后可以执行一个动作来移动标记(例如插入到字符串中)。所有大于当前位置的标记也必须移动以保持正确性。

任务:如何在迭代器不爆炸的情况下更新剩余的标记?我可以刷新迭代器,还是中断并重新开始循环?

以下代码是从我的工作中抽象出来的。

 public void innerLoop(Boolean b) {
    //An Example of what I'm working with
    HashMap<String, HashSet<Integer>> map = new HashMap<String, HashSet<Integer>>() {
        {
            put("Nonce",
                new HashSet<Integer>() {

                {
                    add(1);
                    add(2);
                    add(3);
                    add(4);
                    add(5);
                }
            });
        }
    };

    //for each key
    for (String key: map.keySet()) {
        HashSet<Integer> positions = map.get(key);

        //for each integer
        for (Iterator<Integer> it = positions.iterator(); it.hasNext();) {
            Integer position = it.next();

            System.out.println("position =" + position);
            //(out of scope) decision requiring elements from the outter loops
            if (new Random().nextBoolean()&&b) {
                //shift position by +4 (or whatever)
                //and every other (int >= position)
                System.out.println("Shift " + position + " by 4");
                Integer shift = 4;
                update(position,
                       shift,
                       positions);
                it.remove();
            }
        }
    }
}

public void update(Integer current,
                   Integer diff,
                   Set<Integer> set) {

    if (set != null) {
        HashSet<Integer> temp = new HashSet<Integer>();
        for (Integer old: set) {
            if (old >= current) {
                temp.add(old);
                System.out.println(old + "Added to temp");
            }
        }

        for (Integer old: temp) {
            set.remove(old);
            System.out.println(old + "removed");
            set.add(old + diff);
            System.out.println((old + diff) + "Added");
        }
    }
}

使用 Garrett Hall 解决方案编辑

 public void nestedloops() {

    HashMap<String, HashSet<Integer>> map = new HashMap<String, HashSet<Integer>>() {
        {
            put("Hello",
                new HashSet<Integer>() {

                {
                    add(5);
                    add(2);
                    add(3);
                    add(4);
                    add(1);
                    add(6);
                }
            });
        }
    };

    //for each key
    for (String key: map.keySet()) {
        ArrayList<Integer> positions = new ArrayList<Integer>(map.get(key));
        //for each integer
        for (int i = 0; i < positions.size(); i++) {
            Integer position = positions.get(i);
            System.out.println("[" + i + "] =" + position);
            //out of scope decision
            if (new Random().nextBoolean()) {
                //shift position by +4
                //and every other (int >= position)
                System.out.println("Shift after " + position + " by 4");
                Integer shift = 4;
                //Update the array
                for (int j = 0; j < positions.size(); j++) {
                    Integer checkPosition = positions.get(j);
                    if (checkPosition > position) {
                        System.out.println(checkPosition + "increased by 4");
                        positions.set(j,
                                      checkPosition + shift);
                    }
                }
            }
        }
        //Add updated Array
        map.put(key,
                new HashSet<Integer>(positions));
    }
}
4

2 回答 2

1

你最好的办法是HashSet通过将它放入一个列表来索引它。然后,您可以使用索引来引用元素而不是Iterator. 只要您不删除或添加(仅更新)元素,那么您的索引就是正确的。否则你将不得不考虑这一点。例子:

ArrayList<Integer> positions = new ArrayList<Integer>(map.get(key));
for (int i = 0; i < positions.size(); i ++) {
  // updating list
  for (int j = i; i < positions.size(); j ++) {
    positions.set(j, positions.get(i) + diff);
  }
}
于 2013-10-17T13:58:32.193 回答
0

我会将原始集合复制到一个列表中,这样您就不必担心当前的迭代代码。然后更新一个二级列表(不被迭代)。

原因:

  1. 你不能一次迭代和修改你的原始集合(没有办法绕过ConcurrentModificationExceptions
  2. 很好的一个班轮来移动列表中的项目。

    Collections.rotate(list.subList(j, k+1), -1);
    
  3. Guava将能够处理“找到满足谓词并转换列表的第一个索引”这一系列实用方法。
于 2013-10-17T14:21:52.553 回答