You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin报java.util.ConcurrentModificationException异常如何修复

报错原因

java.util.ConcurrentModificationException是集合的快速失败(fail-fast)机制触发的:所有基于迭代器实现的集合遍历(包括Kotlin的forEach语法糖),都会在迭代器内部维护一个集合修改次数的计数。如果遍历过程中直接调用集合自身的add/remove/clear等会改变集合结构的方法,会导致集合的修改计数和迭代器记录的数值不一致,直接抛出异常。
结合你的代码,核心问题是:你正在遍历的experiments集合,和你执行clear()操作的response.appliedExperiments是同一个对象引用,相当于边遍历同一个集合边清空集合,直接触发了校验。
另外你代码里还有个隐藏的索引越界风险:0..Math.min(...)是 Kotlin 的闭区间写法,边界值会被包含,当response.paymentMethods的长度刚好等于计算出的最小值时,访问paymentMethods[i]会触发数组/列表越界。

修复方案

根据业务场景选以下任意一种方案即可:

  • 方案1:遍历过程中只做逻辑判断,用变量标记是否需要修改集合,等整个遍历流程结束后再执行集合修改操作,这是最稳妥的实现方式:
var shouldClearAppliedExperiments = false
experiments.forEach { experiment ->
    if (NAME_VARIANT == experiment.variantName) {
        val maxTraverseIndex = Math.min(result.size - 1, Constants.MAX_METHODS_APPLIED)
        for (i in 0..maxTraverseIndex) {
            val currentRules = response.paymentMethods[i].scoring.rules!!
            if (currentRules.none { it.ruleName == NAME_RULE }) {
                shouldClearAppliedExperiments = true
            }
        }
    }
}
// 遍历全部完成后再修改集合
if (shouldClearAppliedExperiments) {
    response.appliedExperiments.clear()
}
  • 方案2:如果业务逻辑要求遍历过程中就要修改集合,可以先把待遍历的集合拷贝一份生成快照,遍历快照时修改原集合不会触发校验:
// 把原集合转成不可变副本再遍历
experiments.toList().forEach {
    if(NAME_VARIANT == it.variantName) {
        val maxTraverseIndex = Math.min(result.size - 1, Constants.MAX_METHODS_APPLIED)
        for (i in 0..maxTraverseIndex) {
            if (response.paymentMethods[i].scoring.rules!!.none { it.ruleName == NAME_RULE}) {
                response.appliedExperiments.clear()
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Camila

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 02:36:23