【问题标题】:Concurrent Modification Exception in Java [duplicate]Java中的并发修改异常[重复]
【发布时间】:2012-10-29 17:41:50
【问题描述】:

我在执行此代码时收到 ConcurrentModificationException。我无法弄清楚为什么会这样?

private void verifyBookingIfAvailable(ArrayList<Integer> list, int id) {

        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
                int value = iterator.next();
                if (value == id) {
                    int index = list.indexOf(id);

                    if (index != -1) {
                        list.remove(index);
                    }
                }
        }
    }

提前致谢。

【问题讨论】:

  • 你的代码似乎严格等同于while (list.remove(Integer.valueOf(id)));,除非我遗漏了什么......
  • @assylias。好吧,你没有错过任何东西。你完全正确。根本不需要在这里迭代。不错的收获:)
  • @RohitJain 只需要确保调用的是remove(Object) 而不是remove(int)

标签: java list arraylist concurrentmodification listiterator


【解决方案1】:

您正在使用 list 引用本身删除列表中的元素,这可能会抛出 ConcurrentModificationException。请注意,这有时可能会起作用,但并非总是如此,并且不能保证完美地起作用。

另外,即使你使用Iterator 来迭代你的列表,你仍然不应该使用list.remove,你应该只使用iterator.remove() 来删除元素,否则它不会有任何区别,无论你使用迭代器或增强的 for 循环。

所以,使用iterator.remove() 删除元素。

if (index != -1) {
    iterator.remove(value);
}

请参阅此帖子:-java-efficient-equivalent-to-removing-while-iterating-a-collection 以获得更详细的说明。

【讨论】:

  • tbh,你的回答已经够详细了:)
  • @GanGnaMStYleOverFlowErroR .. 哈哈 :) 可能,但该帖子非常详细,可以与我的答案进行比较。
  • 谢谢,你的回答很全面。
  • @Maverick.. 不客气:)
【解决方案2】:

仅仅是因为您在迭代它们时试图从 ArrayList 中删除元素。要解决此问题,请使用java.util.concurrent.CopyOnWriteArrayList。希望这会有所帮助。

【讨论】:

  • 除非列表用于多线程环境,否则不需要CopyOnWriteArrayList。
【解决方案3】:

发生的情况是 ArrayList 迭代器并非设计为在您对其进行迭代时启用修改。

因此,为了避免来自不连贯数据的更严重的错误,它有一个修改计数,当你删除一个项目时会更新它并在你迭代时检查:

来自 ArrayList.java:

411     public E remove(int index) {
412         rangeCheck(index);
413 
414         modCount++;
415         E oldValue = elementData(index);
416 
417         int numMoved = size - index - 1;
418         if (numMoved > 0)
419             System.arraycopy(elementData, index+1, elementData, index,
420                              numMoved);
421         elementData[--size] = null; // Let gc do its work
422 
423         return oldValue;
424     }
     ...
779 
780         final void checkForComodification() {
781             if (modCount != expectedModCount)
782                 throw new ConcurrentModificationException();
783         }

在 javadoc 中指定:

返回的列表迭代器是快速失败的。

为避免此问题,请使用迭代器移除当前元素,而不是直接移除列表。迭代器的remove 方法确保迭代器保持一致。

【讨论】:

    【解决方案4】:

    试试这个

    private void verifyBookingIfAvailable(ArrayList<Integer> list, int id) {
    
            List<Integer> tempList =new ArrayList<Integer>();
        tempList.addAll(list);
    
         for(Integer value :tempList) {
    
             if (value == 1) {
                 int index = tempList.indexOf(1);
    
                 if (index != -1) {
    
                     list.remove(index);
                 }
             }
     }
    }
    

    在迭代过程中,您正在删除对象

    【讨论】:

    • 还会抛出异常吗??
    • 这是你不应该做的修改列表的开始。然后是迭代器,应该使用它。但即使在迭代器中,也不能使用list.remove。你必须使用iterator.remove。所以你的回答没有帮助。因为,你只是向后退了一步,而不是向前。
    • 我做了一些改变,它可以工作。虽然这可能不是一个好方法
    • @Sura。嗯你是对的。它有效,但复制您的列表不是一个好主意。您应该直接使用迭代器。这就是他们的目的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    相关资源
    最近更新 更多