上一篇
java 怎么遍历json
- 后端开发
- 2025-08-11
- 4
在 Java 中遍历 JSON 可借助第三方库(如 Jackson、Gson、org.json),先将 JSON 字符串解析为
JsonNode
/
JsonObject
(Jackson)或
JsonElement
(Gson),再通过递归或迭代方式遍历键
前置准备:选择适合的JSON处理库
Java生态中有多个成熟的JSON处理库,最常用的三者及其特点如下表所示:
库名称 | 特点 | 适用场景 |
---|---|---|
Jackson | 高性能、功能全面(支持注解绑定/流式API)、广泛集成于Spring框架 | 企业级应用、复杂对象映射 |
Gson | 轻量级、语法简洁、对泛型支持友好 | 快速开发、移动端应用 |
org.json | 纯Java实现、无依赖、API简单直观 | 小型项目、教学演示 |
推荐优先学习Jackson(工业标准)和Gson(简洁高效),二者合计可覆盖90%以上的业务需求。
基于Jackson库的深度遍历方案
环境配置
Maven依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency>
核心实现步骤
步骤①:将JSON字符串转换为JsonNode
对象JsonNode
是Jackson提供的树形结构节点,可灵活访问任意层级的数据。
步骤②:递归遍历节点类型
根据节点类型(对象/数组/值)进行差异化处理:
OBJECT
→ 遍历所有字段名+子节点ARRAY
→ 遍历数组元素VALUE
→ 获取具体值(字符串/数字/布尔值等)
完整代码示例:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.Iterator; import java.util.Map; public class JacksonTraversal { private static void traverse(JsonNode node, String path) { if (node.isObject()) { // 处理JSON对象 Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> entry = fields.next(); String newPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey(); traverse(entry.getValue(), newPath); } } else if (node.isArray()) { // 处理JSON数组 for (int i = 0; i < node.size(); i++) { String newPath = path + "[" + i + "]"; traverse(node.get(i), newPath); } } else { // 基本类型值(终端节点) System.out.println("Path: " + path + " | Value: " + node.toString()); } } public static void main(String[] args) throws IOException { String jsonStr = "{"name":"张三","age":30,"hobbies":["游泳","阅读"],"address":{"city":"北京","street":"长安街"}}"; ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(jsonStr); traverse(rootNode, ""); } }
输出结果:
Path: name | Value: "张三"
Path: age | Value: 30
Path: hobbies[0] | Value: "游泳"
Path: hobbies[1] | Value: "阅读"
Path: address.city | Value: "北京"
Path: address.street | Value: "长安街"
关键技巧:
- 路径拼接:通过
path
参数记录当前节点的访问路径,便于定位数据位置 - 类型判断:必须严格区分
isObject()
和isArray()
,否则会抛出异常 - 空值处理:可通过
node.isNull()
判断空节点,避免NPE
基于Gson库的扁平化遍历方案
环境配置
Maven依赖:
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency>
核心实现思路
Gson默认将JSON转换为Map<String, Object>
或List<Object>
,适合逐层展开的扁平化遍历。
代码示例:
import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import java.util.Stack; public class GsonTraversal { public static void traverse(JsonElement element, String currentPath) { if (element.isJsonObject()) { // 处理JSON对象 JsonObject obj = element.getAsJsonObject(); for (Map.Entry<String, JsonElement> entry : obj.entrySet()) { String newPath = currentPath.isEmpty() ? entry.getKey() : currentPath + "." + entry.getKey(); traverse(entry.getValue(), newPath); } } else if (element.isJsonArray()) { // 处理JSON数组 JsonArray arr = element.getAsJsonArray(); for (int i = 0; i < arr.size(); i++) { String newPath = currentPath + "[" + i + "]"; traverse(arr.get(i), newPath); } } else { // 基本类型值 System.out.println("Path: " + currentPath + " | Value: " + element.toString()); } } public static void main(String[] args) { String jsonStr = "{"name":"李四","scores":[95,88,76],"info":{"gender":"男","height":175}}"; Gson gson = new Gson(); JsonElement root = JsonParser.parseString(jsonStr); traverse(root, ""); } }
输出结果:
Path: name | Value: "李四"
Path: scores[0] | Value: 95
Path: scores[1] | Value: 88
Path: scores[2] | Value: 76
Path: info.gender | Value: "男"
Path: info.height | Value: 175
优势对比:
- Gson的API更简洁,无需显式创建
ObjectMapper
- 对原始类型(如整数、浮点数)的解析更直接
- 适合需要快速验证数据结构的调试场景
特殊场景处理指南
动态键名的遍历(未知结构)
当JSON结构不固定时,需采用通用方式处理:
// Jackson实现 JsonNode dynamicNode = rootNode.get("dynamicKey"); if (dynamicNode != null && !dynamicNode.isMissingNode()) { // 继续遍历... } // Gson实现 if (root.has("dynamicKey")) { JsonElement ele = root.get("dynamicKey"); // 处理逻辑... }
大数据量的内存优化
对于超过1MB的JSON数据,建议改用流式API(仅Jackson支持):
ObjectMapper mapper = new ObjectMapper(); JsonParser parser = mapper.getFactory().createParser(new File("large.json")); while (parser.nextToken() != null) { // 按需处理每个token,避免全量加载到内存 }
复杂类型转换(如日期/枚举)
需配合自定义反序列化器:
// Jackson示例:注册模块处理日期格式 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new Jdk8Module()); // Java8时间类支持 mapper.setDateFormat(df);
常见错误及解决方案
错误类型 | 原因分析 | 解决方法 |
---|---|---|
JsonParseException |
JSON格式非规(如逗号缺失) | 使用在线工具校验JSON格式 |
ClassCastException |
尝试将数组强制转为对象 | 遍历前检查isArray() /isObject() |
UnrecognizedPropertyException |
JSON包含未定义的字段 | 配置@JsonIgnoreProperties 注解 |
OutOfMemoryError |
单次加载过大JSON文件 | 改用流式解析或分割文件 |
相关问答FAQs
Q1: 如何从嵌套JSON中提取特定路径的值?
答:以Jackson为例,可通过链式调用精确定位:
JsonNode cityNode = rootNode.path("address").path("city").get(); // 安全获取方式(不存在返回missing node) String city = cityNode.asText(); // 转换为字符串
若使用Gson,需分段解析:
JsonObject addressObj = root.getAsJsonObject("address"); String city = addressObj.get("city").getAsString();
Q2: 遍历时遇到大量重复键怎么办?
答:JSON规范允许对象内有重复键,但后续值会覆盖前者,若需保留所有值,应改用Multimap
结构存储:
// Jackson解决方案 ObjectMapper mapper = new ObjectMapper(); List<JsonNode> values = mapper.readValue(jsonStr, new TypeReference<List<JsonNode>>(){}); // 后续按索引访问即可避免覆盖问题