Java解析JSON数据案例有吗

wen java案例 1

本文目录导读:

Java解析JSON数据案例有吗

  1. 📖 目录导读
  2. 为什么Java开发者必须掌握JSON解析?
  3. 主流JSON解析库横向对比
  4. 案例一:使用Jackson解析复杂嵌套JSON(最推荐方案)
  5. 案例二:使用Gson处理动态键名与泛型擦除问题
  6. 案例三:Fastjson在高性能场景下的正确打开方式
  7. 案例四:JSON转Java对象时如何处理日期/空值/枚举
  8. 案例五:解析流式JSON(大文件不OOM的秘诀)
  9. 高频问答:面试与实战中常见的8个JSON解析陷阱
  10. 总结:2025年应该选择哪个库?

📖 目录导读

  1. 为什么Java开发者必须掌握JSON解析?
  2. 主流JSON解析库横向对比(Jackson/Gson/Fastjson)
  3. 使用Jackson解析复杂嵌套JSON(最推荐方案)
  4. 使用Gson处理动态键名与泛型擦除问题
  5. Fastjson在高性能场景下的正确打开方式
  6. JSON转Java对象时如何处理日期/空值/枚举
  7. 解析流式JSON(大文件不OOM的秘诀)
  8. 高频问答:面试与实战中常见的8个JSON解析陷阱
  9. 2025年应该选择哪个库?

为什么Java开发者必须掌握JSON解析?

在目前的后端开发中,JSON已经彻底取代XML成为前后端数据交换的“通用语言”,无论是RESTful API、微服务调用、还是配置中心的动态配置,都离不开JSON的序列化与反序列化。一个不精通JSON解析的Java工程师,在面试中几乎不可能通过技术面,而实际开发中,解析错误导致的NullPointerExceptionClassCastException更是让人头疼。


主流JSON解析库横向对比

性能 易用性 依赖体积 独有特性
Jackson 极快 轻量 流式API、树模型
Gson 极高 更轻 支持无注解字段映射
Fastjson 最快(基准测试) 自动识别类型

注意:Fastjson存在历史安全漏洞(如1.2.24之前的版本),推荐使用fastjson2或全面转向Jackson/Gson。


案例一:使用Jackson解析复杂嵌套JSON(最推荐方案)

假设你有如下JSON(常见于订单系统):

{
  "orderId": "10086",
  "user": {"name": "张三", "age": 28, "vip": true},
  "items": [
    {"sku": "A001", "price": 99.5, "count": 2},
    {"sku": "B002", "price": 199.0, "count": 1}
  ],
  "address": null
}

实战代码(Java 8+)

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonNestedDemo {
    public static void main(String[] args) throws Exception {
        String json = "..."; // 上面那段JSON
        ObjectMapper mapper = new ObjectMapper();
        // 方式一:树模型(适合未知结构)
        JsonNode root = mapper.readTree(json);
        String orderId = root.get("orderId").asText();
        String userName = root.path("user").path("name").asText();
        boolean vip = root.path("user").path("vip").asBoolean();
        System.out.println("用户: " + userName + ",VIP: " + vip);
        // 方式二:绑定POJO(推荐用于已知结构)
        Order order = mapper.readValue(json, Order.class);
        double total = order.getItems().stream()
                .mapToDouble(i -> i.getPrice() * i.getCount())
                .sum();
        System.out.println("订单" + order.getOrderId() + "总价: " + total);
    }
}

关键点:使用.path()代替.get(),当字段不存在时返回NullNode而不是null,避免后续空指针。


案例二:使用Gson处理动态键名与泛型擦除问题

场景:解析{"data": {"user_1": {"name": "李四"}, "user_2": {"name": "王五"}}}——键名是动态的。

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import java.util.Map;
public class GsonDynamicKeyDemo {
    public static void main(String[] args) {
        String json = "{\"data\": {\"user_1\": {\"name\": \"李四\"}, \"user_2\": {\"name\": \"王五\"}}}";
        Gson gson = new Gson();
        // 解决泛型擦除:使用TypeToken
        Map<String, Map<String, User>> map = gson.fromJson(json, 
                new TypeToken<Map<String, Map<String, User>>>(){}.getType());
        Map<String, User> users = map.get("data");
        users.forEach((k, v) -> System.out.println(k + " -> " + v.getName()));
    }
    static class User { private String name; }
}

案例三:Fastjson在高性能场景下的正确打开方式

若坚持使用Fastjson(或fastjson2),请务必注意:

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
public class Fastjson2Demo {
    public static void main(String[] args) {
        String json = "{\"code\":200,\"result\":{\"list\":[1,2,3]}}";
        // fastjson2的API与旧版略有不同
        JSONObject obj = JSON.parseObject(json);
        int code = obj.getIntValue("code");
        // 取出list后转成int数组
        int[] list = obj.getJSONObject("result").getObject("list", int[].class);
        System.out.println("code=" + code + ", sum=" + (list[0]+list[1]+list[2]));
    }
}

安全警告:避免使用JSON.parseObject(json, Feature.SupportAutoType),除非你完全信任数据源。


案例四:JSON转Java对象时如何处理日期/空值/枚举

日期处理(Jackson)

ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 或者禁用时间戳:mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

空值处理:默认情况下null字段会被丢弃,若想保留:

mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); // 默认就是ALWAYS
// 想忽略为null的字段:JsonInclude.Include.NON_NULL

枚举反序列化:默认按名字转换,若枚举值是小写:

public enum Status {
    @JsonValue private final String code;
    Status(String code) { this.code = code; }
    @JsonCreator public static Status fromCode(String s) { ... }
}

案例五:解析流式JSON(大文件不OOM的秘诀)

当JSON文件超过500MB,一次性读入内存必然造成OOM,使用Jackson的流式API:

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class StreamingJsonDemo {
    public static void main(String[] args) throws Exception {
        JsonFactory factory = new JsonFactory();
        try (JsonParser parser = factory.createParser(new File("big.json"))) {
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String fieldName = parser.getCurrentName();
                if ("items".equals(fieldName)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        // 每次只处理一个item对象,释放内存
                        if (parser.currentToken() == JsonToken.START_OBJECT) {
                            // 使用parser.readValueAs(Item.class) 或手动解析
                        }
                    }
                }
            }
        }
    }
}

高频问答:面试与实战中常见的8个JSON解析陷阱

Q1:Jackson解析时如何忽略未知字段?

添加@JsonIgnoreProperties(ignoreUnknown = true)注解,或全局配置mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

Q2:Gson解析空字符串到int会报错吗?

会,Gson默认无法将空字符串转为int,需自定义TypeAdapter或字段设为Integer类型。

Q3:Fastjson把0解析成false,怎么修复?

JSON.parseObject(json).getBooleanValue("flag")不行,需使用Integer类型手动判断。

Q4:JSON中有超大数字(超过long范围)怎么办?

Jackson默认会解析成BigInteger,但若绑定到long字段会报错,建议声明字段为LongBigInteger

Q5:如何优雅地处理嵌套JSON的层级过深问题?

使用JsonNode树模型时,层级过深会导致代码繁琐,可以写通用递归方法,或用XPath式路径(Jackson 2.15+的JsonNode.at("/user/address/city"))。

Q6:解析JSON时抛异常,调试思路是什么?

第一看异常栈指向的JSON位置(at [Source: ...; line: 1, column: 11]);第二检查类型是否匹配(如JSON中是"123"字符串,而字段是int)。

Q7:两种库可以混用吗(如用Gson反序列化,Jackson序列化)?

某些场景可以(但性能损耗),如果追求一致性,推荐全项目统一用一个库。

Q8:API返回的JSON字段名是驼峰,但数据库字段是下划线,怎么映射?

Jackson:@JsonProperty("user_name");Gson:@SerializedName("user_name")


2025年应该选择哪个库?

  • 团队新项目:强烈推荐Jackson,它功能最全、性能稳定、社区活跃(Spring Boot默认集成)。
  • 简单小工具Gson用起来最省心,代码量最少。
  • 极端性能需求fastjson2(不要用旧版),但必须升级到安全版本。

最后建议:如果你在写公司新项目,请直接使用Jackson搭配jackson-databind + jackson-datatype-jsr310(处理Java 8时间),它是目前唯一既能处理复杂嵌套、又能流式解析、还不用担心中断更新的库。


行动提示:复制上面案例代码到你的IDE里跑一遍,把JSON换成你项目真实数据结构,立刻掌握解析技巧,如果遇到问题,欢迎在评论区留言详细错误信息,我会挑典型问题回复。

抱歉,评论功能暂时关闭!