编程与 AI12 分钟阅读更新于 2026-07-14

Java 怎么解析 JSON 字符串:对象、数组和字段读取示例

从接口返回、配置读取和日志排查场景出发,讲清 Java 解析 JSON 字符串的常见方法、对象数组区别、字段类型处理、异常排查和格式校验流程。

相关工具

先判断:你拿到的是 JSON 对象还是 JSON 数组

Java 解析 JSON 前,第一件事不是选库,而是看清原始字符串的结构。如果内容以 { 开头,通常是 JSON 对象;如果以 [ 开头,通常是 JSON 数组。对象适合表示一条记录,比如一个用户、一笔订单、一次接口响应;数组适合表示多条记录,比如用户列表、商品列表、日志列表。

很多解析失败并不是 Java 代码写错,而是把数组当对象解析,或者把对象当数组解析。比如接口返回 {"code":0,"data":[...]},最外层是对象,data 字段才是数组。新手经常直接把整段返回当成 List 解析,结果报类型不匹配。正确思路是先解析最外层对象,再读取里面的 data。

调试时建议先把返回内容粘到 JSON 格式化工具里看清层级。不要盯着一整行压缩 JSON 猜字段。格式化后能马上看到 code、message、data、list、total 这些字段的位置,也能判断字段是字符串、数字、布尔值、对象还是数组。

用 Jackson 解析 JSON 对象

Java 项目里常见 JSON 库有 Jackson、Gson、Fastjson 等。Spring Boot 默认更常见 Jackson。假设你已经在项目里有 Jackson,可以这样解析一个简单对象:

java代码示例
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonDemo {
    public static void main(String[] args) throws Exception {
        String json = "{\"name\":\"张三\",\"age\":28,\"city\":\"杭州\"}";
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(json);

        String name = root.path("name").asText();
        int age = root.path("age").asInt();
        String city = root.path("city").asText();

        System.out.println(name + " " + age + " " + city);
    }
}

这里用 readTree 得到 JsonNode,适合调试和灵活读取字段。path 和 get 都能读取字段,但 path 在字段不存在时不会直接返回 null,而是返回 MissingNode,再调用 asText、asInt 时会给默认值。调试阶段用 path 更不容易空指针,但正式业务里仍然要判断字段是否存在。

如果字段结构稳定,也可以定义 Java 类,然后反序列化成对象。比如 User 类有 name、age、city 字段,就可以 mapper.readValue(json, User.class)。这种写法更适合正式业务代码,因为类型更清楚,也方便 IDE 提示。

解析 JSON 数组和列表

如果原始 JSON 是数组,比如 [{"name":"张三"},{"name":"李四"}],可以用 JsonNode 遍历:

java代码示例
String json = "[{\"name\":\"张三\"},{\"name\":\"李四\"}]";
ObjectMapper mapper = new ObjectMapper();
JsonNode array = mapper.readTree(json);

for (JsonNode item : array) {
    System.out.println(item.path("name").asText());
}

如果要转成 List<User>,需要 TypeReference:

java代码示例
import com.fasterxml.jackson.core.type.TypeReference;

List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {});

Java 泛型在运行时会被擦除,所以不能简单写 mapper.readValue(json, List.class) 后就期待它自动变成 List<User>。那样通常得到的是 List<LinkedHashMap>。TypeReference 的作用就是保留泛型信息,让 Jackson 知道列表元素应该是什么类型。

接口响应通常不是直接数据,而是包装结构

真实接口很少直接返回一个用户对象,更多是包装结构,例如:{"code":0,"message":"ok","data":{"id":1,"name":"张三"}}。还有列表结构:{"code":0,"data":{"list":[...],"total":100}}。解析这种结构时,要先读取 code 判断是否成功,再进入 data。

示例写法:

java代码示例
JsonNode root = mapper.readTree(responseBody);
int code = root.path("code").asInt();
if (code != 0) {
    String message = root.path("message").asText();
    throw new RuntimeException("接口失败:" + message);
}
JsonNode data = root.path("data");
String name = data.path("name").asText();

不要只看 HTTP 状态码 200。很多业务接口即使 HTTP 成功,业务 code 也可能失败。解析前先确认接口的成功规则:是 HTTP 200 就算成功,还是 code 为 0 才成功,或者 success 为 true 才成功。这个规则应该来自接口文档。

常见错误和排查方法

第一,JSON 字符串本身不合法。比如字段名没加双引号、末尾多逗号、字符串里有未转义换行。遇到解析异常,先把原始字符串复制到 JSON 校验工具里确认。第二,字段类型不符合预期。接口返回的 age 可能是 "28" 字符串,也可能是 28 数字,直接映射到 int 时要看库是否能自动转换。

第三,字段不存在。path("name").asText() 字段不存在时会返回空字符串,这对调试友好,但可能掩盖问题。正式代码里可以用 has 或 isMissingNode 判断。第四,日期字段格式不一致。比如 createdAt 有时是时间戳,有时是日期字符串,映射到 LocalDateTime 就容易失败。

第五,接口返回的并不是 JSON。有时服务端报错返回 HTML,或者网关返回纯文本错误。Java 代码里看到 JSON parse error,不代表 JSON 库有问题,可能是响应体根本不是 JSON。排查时打印 Content-Type 和响应体前几百个字符很有用。

一套更稳的解析流程

第一步,用 JSON 工具格式化原始内容,确认是对象还是数组。第二步,看最外层结构,找到真正的数据字段。第三步,先用 JsonNode 灵活读取,跑通后再考虑映射成 Java 类。第四步,给缺失字段、类型异常和业务失败留出处理逻辑。第五步,把关键样例保存下来,作为后续单元测试或接口回归数据。

如果你只是临时排查接口,JsonNode 更方便;如果是长期业务代码,定义 DTO 更清楚。比如 UserResponse、UserData、UserItem 分层命名,能让结构一眼看懂。不要把所有字段都塞进 Map<String,Object>,那会让后续维护变得困难。

工具帮的 JSON 格式化、JSON Schema 校验和 API 调试工具适合配合 Java 使用。先用工具确认返回结构,再写 Java 解析代码,能少走很多弯路。尤其是接口字段多、层级深、错误响应复杂时,先看清结构比直接写代码更重要。

常见问题

Java 解析 JSON 用哪个库更好?

Spring Boot 项目常用 Jackson;轻量项目也可以用 Gson。关键不是库名,而是先看清 JSON 结构。

为什么 List<User> 解析出来变成了 LinkedHashMap?

通常是因为用了 List.class,泛型信息丢失。Jackson 里应使用 TypeReference<List<User>>。

接口 200 但解析失败怎么办?

先打印响应体和 Content-Type,确认返回内容真的是合法 JSON,而不是 HTML 或纯文本错误。

Java 实用

继续阅读

返回专题