【问题标题】:How to modify a Collection while iterating using for-each loop without ConcurrentModificationException? [duplicate]如何在没有 ConcurrentModificationException 的情况下使用 for-each 循环进行迭代时修改集合? [复制]
【发布时间】:2011-10-20 23:17:26
【问题描述】:

如果我在使用 for-each 循环迭代集合时修改集合,它会给出ConcurrentModificationException。有什么解决办法吗?

【问题讨论】:

    标签: java collections concurrentmodification


    【解决方案1】:

    使用Iterator#remove

    这是在迭代期间修改集合的唯一安全方法。如需更多信息,请参阅The Collection Interface 教程。

    如果您还需要在迭代时添加元素,请使用ListIterator

    【讨论】:

    • 所以我只是创建该集合的迭代器对象,使用 hasNext() 遍历集合并使用您的建议删除?谢谢。我也可以添加元素吗?
    • @aps,不,您不能添加元素。是的,从集合中获取迭代器。
    • 通过 listIterator.next() 和 listIterator.add() 循环添加新元素仅在两个 'listIterator' 是同一个对象时才有效。
    【解决方案2】:

    一种解决方法是保存您的更改并在循环后添加/删除它们。

    例如:

    List<Item> toRemove = new LinkedList<Item>();
    
    for(Item it:items){
        if(remove){
            toRemove.add(it);
        }
    }
    items.removeAll(toRemove);
    

    【讨论】:

    • 谢谢。我以前也想过这个。但是我有相当多的集合,所以我必须为我拥有的每个集合创建很多冗余的 toRemove 集合。
    【解决方案3】:

    第二种解决方法是使用一个集合类,它的迭代器不会给出异常。比如ConcurrentLinkedQueueConcurrentHashMap等等。

    这些通过为迭代器提供较弱的一致性模型来避免引发异常的需要。 (当然,您需要了解这些模型,并确定它们是否适合您的应用程序。)

    它们通常比非并发集合慢一点,但如果存在严重争用,它们比同步集合包装器快。

    【讨论】:

    • 您能详细说明一下吗?我现在正在使用 LinkedList 吗?使用 ConcurrentLinkedList 会导致性能下降等任何缺点。为什么它不给出例外?修改是否由列表本身处理?
    • 您需要阅读 javadocs 以了解该类的属性。 (对不起,我看错了类名……)
    【解决方案4】:

    如果你只是想从集合中移除元素,你可以使用 Iterator 而不是 Iterable。

    否则,您可以做的不是迭代原始集合,而是首先制作列表的副本。例如,如果您的集合是一个列表,那么您可以创建一个新的 ArrayList(originList) 并对其进行迭代。应该对原始列表进行修改。

    另一种可能更适合您的用例的替代方法不是使用 for-each,而是使用传统的 for-。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-03
      • 2020-06-17
      • 2017-03-25
      • 1970-01-01
      • 1970-01-01
      • 2015-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多