0

0

java使用教程怎样生成和解析JSON数据 java使用教程的JSON处理技巧指南​

絕刀狂花

絕刀狂花

发布时间:2025-08-11 22:52:02

|

778人浏览过

|

来源于php中文网

原创

java中处理json数据的核心是使用jackson或gson等第三方库实现序列化与反序列化,1. 首选jackson因其高性能和丰富功能,通过objectmapper将java对象与json字符串相互转换;2. 使用@jsonproperty、@jsonignore、@jsoninclude等注解处理字段映射、忽略字段和空值过滤;3. 通过@jsonformat或注册javatimemodule统一日期时间格式;4. 对于复杂或动态结构,采用jsonnode树模型灵活遍历,或使用流式api(jsonparser)处理大文件以节省内存;5. 最佳实践中应重用objectmapper实例、配置忽略未知属性、妥善处理异常,并根据场景选择pojo映射或树模型以提升性能和可维护性,从而实现高效、健壮的json处理

java使用教程怎样生成和解析JSON数据 java使用教程的JSON处理技巧指南​

在Java中处理JSON数据,核心在于利用成熟的第三方库,如Jackson或Gson,它们极大地简化了Java对象与JSON字符串之间的相互转换(即序列化与反序列化),使得Java应用能够高效地与外部系统进行数据交换。这不仅仅是简单的字符串操作,更是一种结构化数据的智能映射。

解决方案

谈到Java中的JSON处理,我个人首选Jackson。它功能强大、性能卓越,并且社区活跃,几乎能应对所有你能想象到的JSON场景。当然,Gson也是一个非常好的选择,尤其在安卓开发中很受欢迎,API相对简洁。这里我将以Jackson为例,来演示如何生成和解析JSON数据。

生成JSON数据 (序列化:Java对象 -> JSON字符串)

立即学习Java免费学习笔记(深入)”;

想象一下,我们有一个简单的

Product
类,我们想把它转换成JSON格式。

public class Product {
    private String name;
    private double price;
    private int stock;
    private String category; // 新增字段

    // 构造函数
    public Product(String name, double price, int stock, String category) {
        this.name = name;
        this.price = price;
        this.stock = stock;
        this.category = category;
    }

    // 无参构造函数,Jackson需要
    public Product() {}

    // Getters and Setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public double getPrice() { return price; }
    public void setPrice(double price) { this.price = price; }
    public int getStock() { return stock; }
    public void setStock(int stock) { this.stock = stock; }
    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }

    @Override
    public String toString() {
        return "Product{" +
               "name='" + name + '\'' +
               ", price=" + price +
               ", stock=" + stock +
               ", category='" + category + '\'' +
               '}';
    }
}

要将

Product
对象序列化为JSON字符串,我们使用Jackson的
ObjectMapper

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonGeneratorExample {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        Product product = new Product("Laptop Pro", 1299.99, 50, "Electronics");

        try {
            // 将Java对象转换为JSON字符串
            String jsonString = objectMapper.writeValueAsString(product);
            System.out.println("生成的JSON字符串:\n" + jsonString);

            // 如果需要格式化输出,可以这样:
            String prettyJsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(product);
            System.out.println("\n格式化后的JSON字符串:\n" + prettyJsonString);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

解析JSON数据 (反序列化:JSON字符串 -> Java对象)

现在,我们有了JSON字符串,如何把它变回Java对象呢?同样使用

ObjectMapper

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonParserExample {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonInput = "{\"name\":\"Smartphone X\",\"price\":799.00,\"stock\":200,\"category\":\"Mobile\"}";

        try {
            // 将JSON字符串解析为Java对象
            Product parsedProduct = objectMapper.readValue(jsonInput, Product.class);
            System.out.println("解析后的Java对象:\n" + parsedProduct);

            // 解析一个JSON数组到List
            String jsonArrayInput = "[{\"name\":\"Keyboard\",\"price\":75.50,\"stock\":150,\"category\":\"Accessories\"}," +
                                    "{\"name\":\"Mouse\",\"price\":25.00,\"stock\":300,\"category\":\"Accessories\"}]";

            // 注意这里需要使用TypeReference来处理泛型类型
            java.util.List productList = objectMapper.readValue(jsonArrayInput,
                    new com.fasterxml.jackson.core.type.TypeReference>() {});
            System.out.println("\n解析后的产品列表:");
            productList.forEach(System.out::println);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

别忘了在你的

pom.xml
(如果你用Maven)或
build.gradle
(如果你用Gradle)中添加Jackson的依赖:



    com.fasterxml.jackson.core
    jackson-databind
    2.17.0

Java中如何优雅地处理JSON数据的序列化与反序列化?

在实际开发中,JSON数据的结构往往比我们上面看到的

Product
类复杂得多。优雅地处理这些复杂性,很大程度上依赖于对Jackson(或Gson)高级特性的掌握。这不仅仅是让代码能跑起来,更是让它健壮、可维护。

一个常见的场景是,你的Java对象字段名和JSON中的键名不一致。这时,

@JsonProperty
注解就派上用场了。比如,JSON中可能是
product_name
,而你的Java字段是
name
,你可以这样映射:

public class Product {
    @JsonProperty("product_name") // JSON中的键是product_name
    private String name;
    // ... 其他字段和方法
}

有时候,你可能希望忽略某些字段不进行序列化或反序列化,

@JsonIgnore
能帮你搞定。或者,你只希望在某个字段不为空时才将其包含在JSON中,
@JsonInclude
就非常实用。比如:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_NULL) // 只有非null字段才被序列化
public class User {
    private String username;
    private String email;
    @JsonIgnore // 该字段不会被序列化或反序列化
    private String passwordHash;
    private Integer age; // 可能为null

    // ... 构造函数、getter/setter
}

日期和时间格式化是另一个常遇到的痛点。JSON通常没有内置的日期类型,日期会被表示为字符串。Jackson的

@JsonFormat
注解允许你指定日期字符串的格式,这比手动转换要方便太多了:

import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;

public class Order {
    private String orderId;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    private Date orderDate;
    // ...
}

更进一步,当你需要对某个特定类型进行完全自定义的序列化或反序列化逻辑时,Jackson提供了

JsonSerializer
JsonDeserializer
接口。这允许你编写自己的逻辑来处理那些不遵循标准POJO映射规则的复杂数据类型,比如,一个自定义的枚举类型需要被序列化为特定的字符串,或者一个复杂的业务对象需要聚合多个字段才能反序列化。这给了你极大的灵活性,但通常只在特定、非标准的数据结构场景下才会用到。

文心快码
文心快码

文心快码(Comate)是百度推出的一款AI辅助编程工具

下载

面对复杂或动态JSON结构,Java有哪些高效解析策略?

真实世界的数据往往不是扁平的,JSON结构可能深层嵌套,或者包含动态键名。在这种情况下,直接映射到POJO可能会变得非常笨重,甚至不可能。Jackson提供了两种强大的替代策略:树模型(Tree Model)和流式API(Streaming API)。

树模型(Tree Model)解析

树模型非常适合处理结构不固定、字段缺失或包含未知键的JSON。它将整个JSON数据加载到内存中,构建成一个

JsonNode
树,你可以像操作DOM树一样遍历和查询它。这就像在内存里搭建了一个JSON的“地图”,你可以随意地导航。

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TreeModelExample {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        String complexJson = "{\"id\": \"123\", \"details\": {\"name\": \"Item A\", \"price\": 100.0, \"features\": [\"durable\", \"lightweight\"]}, \"tags\": [\"sale\", \"new\"], \"metadata\": {\"timestamp\": \"2023-10-26\"}}";

        try {
            JsonNode rootNode = objectMapper.readTree(complexJson);

            // 获取基本字段
            String id = rootNode.get("id").asText();
            System.out.println("ID: " + id);

            // 访问嵌套对象
            JsonNode detailsNode = rootNode.get("details");
            if (detailsNode != null && detailsNode.isObject()) {
                String name = detailsNode.get("name").asText();
                double price = detailsNode.get("price").asDouble();
                System.out.println("Details -> Name: " + name + ", Price: " + price);

                // 访问嵌套数组
                JsonNode featuresNode = detailsNode.get("features");
                if (featuresNode != null && featuresNode.isArray()) {
                    System.out.print("Features: ");
                    for (JsonNode feature : featuresNode) {
                        System.out.print(feature.asText() + " ");
                    }
                    System.out.println();
                }
            }

            // 检查字段是否存在
            if (rootNode.has("nonExistentField")) {
                System.out.println("This won't be printed.");
            } else {
                System.out.println("Field 'nonExistentField' does not exist.");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

树模型非常灵活,但缺点是需要将整个JSON加载到内存中,对于非常大的JSON文件可能会有内存压力。

流式API(Streaming API)

当处理超大型JSON文件(例如GB级别)时,内存消耗是主要问题。Jackson的流式API(基于

JsonParser
JsonGenerator
)提供了事件驱动的解析方式,它只在读取或写入数据时处理当前令牌,而不会一次性加载整个JSON。这就像一个SAX解析器,非常高效,但使用起来也更底层、更复杂。你得手动处理每个JSON事件(比如开始对象、结束对象、字段名、字符串值等)。

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import java.io.StringReader;

public class StreamingApiExample {
    public static void main(String[] args) {
        String json = "[{\"name\":\"Laptop\",\"price\":1200},{\"name\":\"Monitor\",\"price\":300}]";
        JsonFactory factory = new JsonFactory();

        try (JsonParser parser = factory.createParser(new StringReader(json))) {
            while (parser.nextToken() != null) {
                JsonToken token = parser.getCurrentToken();
                if (token == JsonToken.FIELD_NAME) {
                    String fieldName = parser.getCurrentName();
                    parser.nextToken(); // 移动到字段值
                    if ("name".equals(fieldName)) {
                        System.out.println("Product Name: " + parser.getText());
                    } else if ("price".equals(fieldName)) {
                        System.out.println("Product Price: " + parser.getValueAsDouble());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

流式API是性能之王,但其编程模型更复杂,通常只在性能是关键瓶颈或内存受限的场景下才考虑使用。

提升Java JSON处理性能与避免常见陷阱的最佳实践

在Java应用中处理JSON,除了选择合适的库和解析策略,还有一些最佳实践可以显著提升性能并避免一些常见的“坑”。

1. 重用

ObjectMapper
实例
ObjectMapper
的创建成本并不低,它内部维护了一些缓存和配置信息。因此,在你的应用中,应该尽可能地重用同一个
ObjectMapper
实例,而不是每次序列化或反序列化都创建一个新的。将其声明为单例或注入到Spring/Guice等框架中是一个好方法。

// 推荐做法:在应用启动时创建一次,并全局复用
public class GlobalObjectMapper {
    public static final ObjectMapper INSTANCE = new ObjectMapper();
    static {
        // 可以进行一些全局配置,例如:
        // INSTANCE.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // INSTANCE.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }
}

// 使用时
// String json = GlobalObjectMapper.INSTANCE.writeValueAsString(myObject);

2. 谨慎处理未知属性 默认情况下,Jackson在反序列化时如果遇到JSON中存在但Java POJO中没有的字段,会抛出

UnrecognizedPropertyException
。这在某些情况下是好事,因为它能帮助你发现数据模型不匹配的问题。但有时,你可能希望忽略这些未知字段,特别是在与不完全受控的第三方API交互时。可以通过配置
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
来改变这一行为:

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

我通常会根据业务场景来决定是否开启这个,如果数据源可靠且模型需要严格匹配,保持默认(true)可以帮助发现问题;如果数据源可能包含额外字段,或者为了向后兼容,设为

false
会更灵活。

3. 日期/时间处理的统一性 日期时间是JSON处理中最容易出错的地方。确保你的Java代码和JSON数据的日期时间格式保持一致。除了前面提到的

@JsonFormat
,你也可以全局配置
ObjectMapper
的日期格式:

import java.text.SimpleDateFormat;
import java.util.TimeZone;

// ...
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设定时区

或者,如果你使用Java 8的

java.time
包(推荐),需要额外引入
jackson-datatype-jsr310
模块,并注册到
ObjectMapper
中:


    com.fasterxml.jackson.datatype
    jackson-datatype-jsr310
    2.17.0
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

// ...
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule()); // 注册Java 8日期时间模块

这样,

LocalDateTime
,
Instant
等类型就能被Jackson正确处理了。

4. 异常处理 JSON处理过程中可能会遇到

IOException
(例如,读取或写入文件时)和
JsonProcessingException
(Jackson特有的,表示JSON格式不正确或序列化/反序列化失败)。始终使用
try-catch
块来捕获这些异常,并进行适当的日志记录或错误处理,避免程序崩溃。

try {
    String json = objectMapper.writeValueAsString(data);
} catch (JsonProcessingException e) {
    // 处理JSON序列化失败的情况
    System.err.println("JSON序列化失败: " + e.getMessage());
    // 记录日志 e.printStackTrace();
} catch (IOException e) {
    // 处理IO操作失败的情况
    System.err.println("IO操作失败: " + e.getMessage());
}

5. 避免不必要的POJO创建 对于只需要读取JSON中少数几个字段的场景,或者JSON结构过于复杂且大部分字段不关心时,可以考虑使用树模型(

JsonNode
)而不是强行创建POJO。这样可以减少POJO类的数量,并避免不必要的对象实例化,从而节省内存和CPU周期。

JSON处理是现代Java应用中不可或缺的一部分。掌握这些技巧,不仅能让你的代码更健壮,也能在性能和维护性上获得显著提升。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

825

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

724

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

728

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

395

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

445

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

428

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16861

2023.08.03

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

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

精品课程

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

共28课时 | 2.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.0万人学习

Kotlin 教程
Kotlin 教程

共23课时 | 2.1万人学习

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

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