0

0

Groovy中安全修改JSON数据:避免并发修改异常与文件更新实践

碧海醫心

碧海醫心

发布时间:2025-11-08 17:51:01

|

476人浏览过

|

来源于php中文网

原创

Groovy中安全修改JSON数据:避免并发修改异常与文件更新实践

本文旨在深入探讨在groovy中处理json数据时,如何安全地删除匹配条件的元素并更新文件,同时避免常见的`concurrentmodificationexception`。我们将介绍两种核心策略:通过`findall`方法生成一个过滤后的新json对象,以及利用迭代器(iterator)在遍历过程中安全地移除现有对象中的元素。文章将提供详细的代码示例和最佳实践,帮助开发者高效、稳定地管理json数据。

在Groovy中,处理JSON数据是常见的任务。当我们需要根据特定条件删除JSON对象中的元素时,直接在迭代过程中修改原始集合(如Map)往往会导致java.util.ConcurrentModificationException。这是因为当一个集合正在被迭代器遍历时,如果其底层结构被直接修改(例如添加或删除元素),迭代器会检测到这种并发修改并抛出异常,以防止不确定的行为。

本教程将提供两种健壮且Groovy风格的解决方案来解决这个问题,并演示如何将修改后的JSON数据写回文件。

1. 理解ConcurrentModificationException

ConcurrentModificationException通常发生在以下场景:你正在使用迭代器(隐式或显式)遍历一个集合,同时又通过集合本身的add()、remove()等方法修改这个集合。Groovy的each闭包在内部也使用了迭代器,因此直接在each循环中调用json.remove(key)会触发此异常。

例如,以下代码片段会抛出异常:

import groovy.json.*

def jsonSlurper = new JsonSlurper()
def jsonContent = '''
{
    "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"
    }
}'''
def json = jsonSlurper.parseText(jsonContent)

// 错误示例:直接在each循环中修改json对象
json.each { key, val ->
    if ("foo-web" == val.name) {
        json.remove(key) // 这将导致ConcurrentModificationException
    }
}

2. 解决方案一:创建新的过滤后JSON对象

这是推荐的Groovy风格解决方案之一。它通过findAll方法创建一个新的Map(或List),其中只包含满足指定条件的元素。这种方法不会修改原始对象,因此是完全安全的。

2.1 核心思路

使用Map.findAll()方法遍历原始JSON对象(在Groovy中解析的JSON对象通常是Map类型),并根据条件筛选出需要保留的元素。findAll会返回一个新的Map,其中包含所有满足闭包条件的键值对

2.2 代码示例

import groovy.json.*

// 模拟从文件加载JSON内容
def jsonContent = '''\
{
    "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"
    },
    "stack-2": {
        "name": "foo-web",
        "createdAt": "2022-11-30T10:56:32.551977633Z",
        "dbName": "foo-DB"
    }
}'''
def originalJson = new JsonSlurper().parseText(jsonContent)

println "原始JSON: ${originalJson}"

// 创建一个过滤后的新Map,保留所有name不等于"foo-web"的元素
def filteredJson = originalJson.findAll { key, val ->
    'foo-web' != val.name
}

println "过滤后的JSON: ${filteredJson}"

// 预期输出:
// 过滤后的JSON: [stack-1:[name:bar-web, createdAt:2022-11-30T10:56:32.551977633Z, dbName:bar-DB]]
assert filteredJson.toString() == '[stack-1:[name:bar-web, createdAt:2022-11-30T10:56:32.551977633Z, dbName:bar-DB]]'

// 此时 originalJson 仍然保持不变
println "原始JSON(未改变): ${originalJson}"

2.3 优点与适用场景

  • 安全性高: 不会修改原始对象,避免ConcurrentModificationException。
  • 简洁性: Groovy的findAll方法使得代码非常简洁易读。
  • 函数式风格: 符合函数式编程中不可变数据的思想。
  • 适用场景: 当你可以接受创建一个新的JSON对象作为结果,或者需要保留原始JSON对象以供后续使用时。

3. 解决方案二:使用迭代器(Iterator)安全地修改现有JSON对象

如果出于性能考虑(例如处理非常大的JSON数据,避免创建新对象带来的内存开销),或者你必须修改原始JSON对象的引用,那么使用迭代器是正确的选择。

赣极购物商城网店建站软件系统
赣极购物商城网店建站软件系统

大小仅1兆左右 ,足够轻便的商城系统; 易部署,上传空间即可用,安全,稳定; 容易操作,登陆后台就可设置装饰网站; 并且使用异步技术处理网站数据,表现更具美感。 前台呈现页面,兼容主流浏览器,DIV+CSS页面设计; 如果您有一定的网页设计基础,还可以进行简易的样式修改,二次开发, 发布新样式,调整网站结构,只需修改css目录中的css.css文件即可。 商城网站完全独立,网站源码随时可供您下载

下载

3.1 核心思路

获取JSON对象(Map)的迭代器,然后通过迭代器提供的remove()方法来删除元素。Iterator.remove()是唯一在迭代过程中安全修改集合的方法。

3.2 代码示例

import groovy.json.*

// 模拟从文件加载JSON内容
def jsonContent = '''\
{
    "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"
    },
    "stack-2": {
        "name": "foo-web",
        "createdAt": "2022-11-30T10:56:32.551977633Z",
        "dbName": "foo-DB"
    }
}'''
def mutableJson = new JsonSlurper().parseText(jsonContent)

println "原始JSON (可变): ${mutableJson}"

// 使用迭代器安全地修改现有json对象
def entry
for (Iterator iter = mutableJson.entrySet().iterator(); iter.hasNext();) {
    entry = iter.next()
    if ('foo-web' == entry.value.name) {
        iter.remove() // 使用迭代器自身的remove方法
    }
}

println "修改后的JSON (原地修改): ${mutableJson}"

// 预期输出:
// 修改后的JSON (原地修改): {stack-1={name=bar-web, createdAt=2022-11-30T10:56:32.551977633Z, dbName=bar-DB}}
assert mutableJson.toString() == '{stack-1={name=bar-web, createdAt=2022-11-30T10:56:32.551977633Z, dbName=bar-DB}}'

3.3 优点与适用场景

  • 原地修改: 直接修改现有对象,不产生新的对象引用,节省内存。
  • 安全性: Iterator.remove()是唯一允许在迭代过程中修改集合的方法。
  • 适用场景: 当处理非常大的数据集,内存优化是关键时;或者当必须保持原始对象的引用不变时。

4. 将修改后的JSON数据写回文件

无论你选择了哪种修改JSON数据的方法,最终都需要将结果写回文件。这可以通过JsonBuilder和File.write()方法实现。

4.1 核心思路

使用JsonBuilder将Groovy对象(Map)转换回JSON格式的字符串,然后使用File.write()方法将字符串写入文件。为了保持可读性,通常会使用toPrettyString()方法。

4.2 代码示例

结合上述两种解决方案中的任意一种,假设我们已经得到了filteredJson或mutableJson。

import groovy.json.*

// 假设 filteredJson 是通过 findAll 得到的
// 或者 mutableJson 是通过 Iterator 修改的
def finalJsonData = [
    "stack-1": [
        "name": "bar-web",
        "createdAt": "2022-11-30T10:56:32.551977633Z",
        "dbName": "bar-DB"
    ]
] as Map // 示例数据,实际应为 filteredJson 或 mutableJson

// 将Groovy Map转换为格式化的JSON字符串
def newJsonString = new JsonBuilder(finalJsonData).toPrettyString()

// 定义文件路径
def filePath = "sarva.json"
def outputFile = new File(filePath)

// 将JSON字符串写入文件
outputFile.write(newJsonString)

println "已将更新后的JSON数据写入 ${filePath}。"
println "文件内容:\n${outputFile.text}"

// 验证文件内容
assert outputFile.text.trim() == '''{
    "stack-1": {
        "name": "bar-web",
        "createdAt": "2022-11-30T10:56:32.551977633Z",
        "dbName": "bar-DB"
    }
}'''.trim()

// 清理:删除生成的文件
outputFile.delete()

4.3 注意事项

  • 文件路径: 确保文件路径正确且Groovy脚本有写入权限。
  • 编码 默认情况下,write()方法使用平台默认编码。如果需要指定编码,可以使用outputFile.write(newJsonString, 'UTF-8')。
  • 错误处理: 在生产环境中,建议添加try-catch块来处理文件操作可能出现的IOException。

5. 总结

在Groovy中安全地从JSON对象中删除元素并更新文件,关键在于避免ConcurrentModificationException。我们提供了两种主要策略:

  1. 使用findAll方法: 创建一个新的、过滤后的JSON对象。这种方法简洁、安全,且符合函数式编程范式,适用于大多数场景。
  2. 使用Iterator.remove()方法: 在遍历过程中直接修改原始JSON对象。这种方法在需要原地修改或处理超大数据集时更为高效。

无论选择哪种方法,最终都可以通过JsonBuilder将修改后的数据序列化为JSON字符串,并使用File.write()方法将其持久化到文件中。理解这些策略并根据具体需求选择合适的方法,将帮助你编写出更健壮、高效的Groovy JSON处理代码。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

454

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

546

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

334

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1565

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

649

2023.11.24

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.1万人学习

Java 教程
Java 教程

共578课时 | 80.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号