即使使用迭代器,从ArrayList中删除元素时仍会出现java.util.ConcurrentModificationException异常

4
我正在尝试在满足特定条件时从两个ArrayList中删除内容。但是当条件满足时,我会收到并发修改错误。在互联网上搜索后,我看到了使用迭代器概念来解决此问题的解决方案,但这也不起作用。
以下是我尝试的两种代码变化:[我的代码是Kotlin]
第一种变化:删除后立即出现错误
        var index = 0
        for (snap: DataSnapshot in snaps){
            if (snap.key == snapshot.key){
                snaps.removeAt(index)
                emailOfSenders.removeAt(index)
            }

            index++
        }

第二种变化:如果ArrayList中的项少于3个,则有效,但如果项为3个或多于3个,则我会收到相同的错误。

        var index = 0

        val iter: Iterator<DataSnapshot> = snaps.iterator()
        while (iter.hasNext()) {
            val snap: DataSnapshot = iter.next()
            if (snap.key == snapshot.key){
                snaps.removeAt(index)
                emailOfSenders.removeAt(index)
            }

            index++
        }

错误日志:

2020-11-18 13:52:32.829 18935-18935/com.rofy.snapyandroid E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.rofy.snapyandroid, PID: 18935
    java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.next(ArrayList.java:860)
        at com.rofy.snapyandroid.SnapsActivity$onCreate$1.onChildRemoved(SnapsActivity.kt:54)
        at com.google.firebase.database.core.ChildEventRegistration.fireEvent(ChildEventRegistration.java:88)
        at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
        at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

更多信息:我正在创建一个类似 Snapchat 的应用程序,并使用谷歌的 Firebase 进行开发。一切工作都很完美,包括在 Firebase 中上传、下载和删除,因此我认为这不是 Firebase 的问题。


1
应该是匹配元素在列表中最后一个的情况。使用迭代器时,只能使用iterator.remove()方法。 - Gaurav Jeswani
1个回答

8
如果您正在使用迭代器遍历集合,则只能使用迭代器的修改器方法来修改集合,如果尝试使用集合的修改器方法(如remove、set等)修改集合,则迭代器会抛出ConcurrentModificationException,这被称为迭代器的fail-fast属性。
在您的情况下,您应该使用iterator.remove()而不是snaps.removeAt(index)。
请注意,iterator.remove()删除迭代器返回的最后一个元素。因此,为了删除一个元素,您必须先调用next()方法。例如,假设您想要删除第一个元素。为了实现这一点,您需要执行以下操作。
iterator.next()
iterator.remove() // Removes the element returned by next

如果ArrayList中的项少于3个,则可以正常工作,但是如果项大于3个,则会出现相同的错误。
这是因为ConcurrentModificationExceptionnext()方法抛出,在1或2个元素的情况下,它仅被调用一次,并且在任何修改之前,因此您不会收到任何错误。在上述情况下,执行以下步骤:
1. iterator.hasNext()      // returns true 
2. iterator.next()         // works fine, since we have not modified collection yet
3. snaps.removeAt(index)   // removes one element
4. iterator.hasNext()      // returns false as there is only one element in list
5. iterator.next           // this line is not executed and hence no error

非常感谢您详细的解释 :) 。我终于明白我做错了什么。您的解决方案帮助了我。谢谢 :D - user8883996

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接