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

Groovy删除JSON匹配元素时遇ConcurrentModificationException问题求助

解决Groovy遍历JSON时删除元素引发的ConcurrentModificationException错误

问题场景

加载JSON文件并遍历元素,删除匹配指定值的元素后生成新JSON。当JSON仅含一个元素时可成功删除,但存在两个元素时触发java.util.ConcurrentModificationException错误。

现有sarva.json文件内容

{
    "stack-0": {
        "name": "foo-web",
        "createdAt": "2022-11-30T10:56:32.551977633Z",
        "dbName": "foo-DB"
    },
    "stack-1": {
        "name": "bar-web",
        "createdAt": "2022-11-30T10:56:32.551977633Z",
        "dbName": "bar-DB"
    }
}

报错代码

import groovy.json.*

def jsonSlurper = new JsonSlurper()
def json = jsonSlurper.parse(new File("sarva.json"))
json.each { key, val ->
if ("$val.name" == "foo-web") {
  json.remove(key)
  println json
}
}

// 更新sarva.json文件

newJson = new JsonBuilder(json).toPrettyString()
new File("sarva.json").write(newJson)

报错信息

[stack-1:[createdAt:2022-11-30T10:56:32.551977633Z, dbName:bar-DB, name:bar-web]]
java.util.ConcurrentModificationException
    at java.base/java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1208)
    at java.base/java.util.TreeMap$EntryIterator.next(TreeMap.java:1244)
    at java.base/java.util.TreeMap$EntryIterator.next(TreeMap.java:1239)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2201)
    at org.codehaus.groovy.runtime.dgm$164.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
    at Script1.run(Script1.groovy:5)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:574)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:612)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:583)
    at hudson.util.RemotingDiagnostics$Script.call(RemotingDiagnostics.java:149)
    at hudson.util.RemotingDiagnostics$Script.call(RemotingDiagnostics.java:118)
    at hudson.remoting.LocalChannel.call(LocalChannel.java:47)
    at hudson.util.RemotingDiagnostics.executeGroovy(RemotingDiagnostics.java:115)
    at jenkins.model.Jenkins._doScript(Jenkins.java:4729)
    at jenkins.model.Jenkins.doScript(Jenkins.java:4700)

解决方案

原因分析

ConcurrentModificationException的触发原因是:在遍历集合(此处为TreeMap,由JsonSlurper解析生成)的同时,直接修改了集合的结构(执行remove操作),集合的迭代器会检测到这种并发修改并抛出异常。

方法一:遍历集合的副本

通过遍历原集合的keySet副本,避免在遍历过程中修改原集合的结构:

import groovy.json.*

def jsonSlurper = new JsonSlurper()
def json = jsonSlurper.parse(new File("sarva.json"))

// 遍历keySet的副本,避免遍历原集合时修改结构触发异常
json.keySet().toList().each { key ->
    def val = json[key]
    if (val.name == "foo-web") {
        json.remove(key)
        println json
    }
}

def newJson = new JsonBuilder(json).toPrettyString()
new File("sarva.json").write(newJson)

方法二:生成过滤后的新集合(推荐)

利用Groovy的findAll方法直接生成过滤后的新Map,无需修改原集合,代码更简洁且符合函数式编程风格:

import groovy.json.*

def jsonSlurper = new JsonSlurper()
def json = jsonSlurper.parse(new File("sarva.json"))

// 过滤出name不等于"foo-web"的元素,生成新Map
def filteredJson = json.findAll { key, val ->
    val.name != "foo-web"
}

println filteredJson
def newJson = new JsonBuilder(filteredJson).toPrettyString()
new File("sarva.json").write(newJson)

预期输出

执行上述代码后,控制台输出:

[stack-1:[createdAt:2022-11-30T10:56:32.551977633Z, dbName:bar-DB, name:bar-web]]

sarva.json文件仅保留stack-1的信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:45:31