unsure whether this is the correct channel but nee...
# getting-started
m
unsure whether this is the correct channel but need help to figuring out why I got
ConcurrentModificationException
when iterating (and modify) a mutable list. detail in thread 🧵
currently, I have a mutable list of weak ref and I have a use case to remove weak ref from the list during
forEach
iteration. am I missing something here? snippet of the relevant code:
Copy code
class Bindable<T>() {
    private val bindings: WeakReferenceList<Bindable<T>> = mutableWeakListOf()

    fun unbindFrom(bindable: Bindable<T>) {
        removeBinding(bindable.weakReference)
        bindable.removeBinding(weakReference)
    }

    private fun removeBinding(ref: WeakReference<Bindable<T>>) {
        bindings.remove(ref)
    }

    fun unbindBindings() {
        if (bindings.isNotEmpty()) {
            bindings.forAliveRefs { it.unbindFrom(this) }
            bindings.clear()
        }
    }
}
Copy code
internal class WeakReferenceList<T>(private val delegate: MutableList<WeakReference<T>>) :
    MutableList<WeakReference<T>> by delegate {

    override fun contains(element: WeakReference<T>): Boolean = synchronized(this) {
        return delegate.any { it.get()?.equals(element) ?: false }
    }

    fun forAliveRefs(clearDestroyedRefs: Boolean = true, action: (T) -> Unit) = synchronized(this) {
        if (clearDestroyedRefs) removeDestroyedRefs()

        delegate.forEach { it.get()?.let(action) }
    }
}
got
ConcurrentModificationException
on
forEach
line
tried method provided on the internet by using
iterator
but still no luck
r
You are calling the
MutableList.remove
function while iterating the list with
forEach
, which does indeed cause this exception with certain list implementations (not sure which one you are using here). Not sure what you mean with your last remark, but when using a Java
iterator
you can call
iterator.remove()
which is safe to perform even while iterating. Alternatively you can use another List implementation that does support concurrent modification, but that might be overkill in this scenario.
🙌 1
m
aha, so removing item while iterating the list the culprit here. and yeah I tried to use
delegate.iterator()
to iterate the list but the since the remove action are passed as function param so I can't use
iterator.remove()
.
solved by filtering out the items before doing the action. not sure if it's the best approach here but it's working 😅
Copy code
fun getAliveRefs(): List<WeakReference<T>> = synchronized(this) {
    delegate.filter { it.get() != null }
}

fun forAliveRefs(action: (T) -> Unit) = synchronized(this) {
    getAliveRefs().forEach { it.get()?.let(action) }
}