【问题标题】:Java - adding elements to list while iterating over itJava - 在迭代时将元素添加到列表中
【发布时间】:2012-07-22 09:05:30
【问题描述】:

我想避免收到ConcurrentModificationException。我该怎么做?

【问题讨论】:

标签: java arraylist iterator


【解决方案1】:

您可以使用ListIterator,它在迭代过程中支持删除/添加方法。

ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
    if(iter.next().getIsbn().equals(isbn)){
        iter.add(new Book(...));
    }
}

【讨论】:

  • 有趣,我不知道这门课。这与 JimN 的解决方案不同之处在于它将插入 inline 而不是添加到末尾。虽然我不确定这是 OP 所要求的(尽管现在我再次查看时存在歧义),但我给你一个 +1,因为它确实实现了将元素添加到列表中。
【解决方案2】:

您可以使用带索引的 for 循环,而不是使用迭代器。例如:

int originalLength = list.length();
for (int i = 0; i < originalLength; i++) {
  MyType mt = list.get(i);
  //... processing
  //... insertions
}

【讨论】:

  • +1 以获得add(T) 操作的最佳解决方案,这正是我们所要求的。
  • 唯一明显的问题是,如果列表实现不提供随机访问(即 LinkedList),您将不得不付出性能损失。例如,在 LinkedList 中,每次执行 get(i) 时,都必须访问所有节点,直到到达节点 i。恕我直言,这不是一个好方法。
  • @JimN 你通过访问每个索引给 jvm 造成负担,这不是一个好方法
  • @Edwin 虽然如果用户使用的是 LinkedList,这是一个公平的观点,但问题确实有 arraylist 标签。
【解决方案3】:

您想使用ListIterator。您可以从任何类型的列表中获取其中一个,但为了提高效率,您可能希望从LinkedList 中获取一个。

import java.util.*;
class TestListIterator {
  public static void main(String[]args) {
    List<Integer> L = new LinkedList<Integer>();
    L.add(0);
    L.add(1);
    L.add(2);
    for (ListIterator<Integer> i = L.listIterator(); i.hasNext(); ) {
      int x = i.next();
      i.add(x + 10);
    }
    System.out.println(L);
  }
}

打印[0, 10, 1, 11, 2, 12]

【讨论】:

    【解决方案4】:

    创建一个新列表并填充该列表。

    List<MyType> originalList = ...
    List<MyType> newList = new ArrayList<>(originalList);
    
    for(MyType type : originalList)
    {
      // Some decisions
      newList.add(new MyType());
    }
    

    【讨论】:

    • 没有更实用的吗?这将是一个重复的操作,我想避免复制这么多。还是应该只为新对象使用一个临时列表并在最后合并两个列表?
    • originalList.addAll(newList);应该添加。
    • @stacker 如果您再次阅读代码,您会发现这会导致重复。如果您想将其存储在第一个列表中,您可以使用originalList = newList;。不过这并不重要,因为 JimN 的解决方案更适合 add(T) 操作。
    【解决方案5】:

    有三种方法可以避免上述异常

    1. 您可以将列表转换为数组,然后对数组进行迭代。这种方法适用于中小型列表,但如果列表很大,则会对性能产生很大影响。

    2. 您可以在迭代时锁定列表,方法是将其放入同步块中。不推荐使用这种方法,因为它会失去多线程的好处。

    3. 如果您使用的是 JDK1.5 或更高版本,则可以使用 ConcurrentHashMap 和 CopyOnWriteArrayList 类。这是推荐的方法。

    【讨论】:

    • 我确实有一个同步块,但问题仍然存在:synchronized (ballsLocal) { initialSize = ballsLocal.size(); for (int i = 0; i
    • 同步只防止其他线程;如果他从同一个线程进行迭代和插入,那么#2 没有帮助。 #3 同上。
    • 我看不出同步将如何阻止ConcurrentModificationException。此异常发生在单线程代码中。我错过了什么吗?
    猜你喜欢
    • 2011-11-16
    • 2023-04-02
    • 2014-10-28
    • 2015-02-07
    • 1970-01-01
    • 2012-05-08
    • 2014-01-02
    • 2020-08-19
    • 1970-01-01
    相关资源
    最近更新 更多