Java - 在浏览时将元素添加到ArrayList

时间:2015-12-30 01:47:09

标签: java

问题是我有这个方法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树。

4 个答案:

答案 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)的情况,这不会太难,但我不知道实现是否这样做)。但是,对于ArrayListget(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());
}