问题是我有这个方法createNode()
在树中创建一个节点,然后如果它离开节点就把它添加到ArrayList<Tree> treeLeaves
中,我打电话浏览treeLeaves
ArrayList时的方法,如下所示:
Iterator<Tree> iter = treeLeaves.iterator();
while (iter.hasNext()) {
iter.next().createNode();
}
或者像这样:
For (Tree cursor : treeLeaves) {
cursor.createNode();
}
但我一直有这个例外:
Exception in thread "main" java.util.ConcurrentModificationException
即使将下面的代码放在snychronized(treeLeaves){}
块中。
P.S:我不知道这是否有用但是;它是一棵n树。
答案 0 :(得分:5)
你需要一个ConcurrentList ......
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
阅读Is there a concurrent List in Java's JDK?
此外,您无法在浏览时更改arraylist ...相反,您可以使用tempoaray内存中的缓冲区编辑当前列表(如果您愿意)。
答案 1 :(得分:2)
对于ArrayList
,只需使用索引就可以避免使用迭代器:
for (int i = 0; i < treeLeaves.size(); i++) {
Tree current = treeLeaves.get(i);
// your code
}
只要你做的唯一事情是附加到数组的末尾,并且你没有插入中间或开头或删除任何项目,这将是有效的。每次进行循环时都会重新计算treeLeaves.size()
,这意味着如果您追加到最后,将重新计算大小,i
将转到新项目。是的,使用老式循环并不像迭代器那样“酷”,但它确实有效。
我建议不要将此List
用于ArrayList
以外的任何类型,因为通常get(i)
必须从列表的开头开始并逐步完成每个元素(除非运行时优化get(i+1)
后使用get(i)
的情况,这不会太难,但我不知道实现是否这样做)。但是,对于ArrayList
,get(i)
应该花费不变的时间。
答案 2 :(得分:1)
这是因为在Java中,当创建Iterator时,您无法修改基础数据结构。增强的for循环“for(Tree cursor:treeLeaves)”“使用Iterator。
正如Ya所说,“你也无法在浏览时改变一个arraylist ...而是你可以使用tempoaray内存中的缓冲区来编辑当前列表。”
答案 3 :(得分:0)
简而言之,在大多数情况下,如果更改集合的结构,则所有仍未打开的迭代器将变为无效。 (相当一些例外,包括使用Concurrent集合,或通过迭代器等进行修改。)
您的问题可以通过以下方式轻松证明:
List<Node> treeLeaves = new ArrayList<>();
//... add something to treeLeaves
for (leaf : treeLeaves) {
treeLeaves.add(new Node());
}
对于您的情况,可以通过创建迭代的新集合轻松解决:
List<Node> treeLeaves = new ArrayList<>();
//... add something to treeLeaves
List<Node> tempLeaves = new ArrayList<>(treeLeaves);
for (leaf : tempLeaves ) {
treeLeaves.add(new Node());
}