You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新手求指导:Java中对比两个JSON文件的最优实现方案

Hey there! 刚接触JSON处理就碰到文件对比的需求很正常,我来给你梳理几个Java里处理这类需求的最优方案,结合你给出的嵌套JSON结构,应该能帮你快速上手~

方案1:用专门的JSON对比库(新手首选,省心高效)

这类库已经封装好了JSON对比的核心逻辑,不用自己写递归遍历,适合快速实现需求。推荐两个常用的:

JSONAssert

它是Apache生态下的工具库,支持灵活的对比规则(比如忽略字段顺序、忽略特定字段、模糊匹配值)。

步骤:

  1. 导入Maven依赖(如果用Maven的话):
<dependency>
    <groupId>org.skyscreamer</groupId>
    <artifactId>jsonassert</artifactId>
    <version>1.5.1</version>
    <scope>test</scope> <!-- 如果是业务代码可以去掉test scope -->
</dependency>
  1. 读取两个JSON文件的内容为字符串,然后调用对比方法:
import org.skyscreamer.jsonassert.JSONAssert;
import java.nio.file.Files;
import java.nio.file.Paths;

public class JsonComparator {
    public static void main(String[] args) throws Exception {
        // 读取两个JSON文件内容
        String json1 = new String(Files.readAllBytes(Paths.get("file1.json")));
        String json2 = new String(Files.readAllBytes(Paths.get("file2.json")));
        
        // 宽松对比(忽略字段顺序,适合你的嵌套对象场景)
        JSONAssert.assertEquals(json1, json2, false);
        
        // 如果需要忽略特定字段(比如示例里的RDate字段),可以用自定义配置
        // JSONAssert.assertEquals(json1, json2, new CustomComparator(JSONCompareMode.LENIENT, 
        //     new Customization("*.RDate", (o1, o2) -> true)));
    }
}

JsonUnit

另一个语法更友好的库,支持断言式对比,上手更简单:

<dependency>
    <groupId>org.json-unit</groupId>
    <artifactId>json-unit</artifactId>
    <version>2.32.0</version>
</dependency>

示例代码:

import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals;
import java.nio.file.Files;
import java.nio.file.Paths;

public class JsonUnitDemo {
    public static void main(String[] args) throws Exception {
        String json1 = new String(Files.readAllBytes(Paths.get("file1.json")));
        String json2 = new String(Files.readAllBytes(Paths.get("file2.json")));
        
        // 宽松对比,忽略字段顺序和多余字段
        assertJsonEquals(json1, json2, 
            net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER,
            net.javacrumbs.jsonunit.core.Option.IGNORING_EXTRA_FIELDS);
    }
}
方案2:用Jackson树模型手动对比(灵活度拉满,适合自定义规则)

如果你需要更精细的控制(比如处理带逗号的数字字符串、"Not Found"这类特殊值),可以用Jackson的JsonNode树模型,手动递归遍历对比每个节点。

示例代码:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CustomJsonComparator {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws Exception {
        JsonNode node1 = mapper.readTree(Files.readAllBytes(Paths.get("file1.json")));
        JsonNode node2 = mapper.readTree(Files.readAllBytes(Paths.get("file2.json")));
        
        boolean isEqual = compareJsonNodes(node1, node2);
        System.out.println("两个JSON是否相等:" + isEqual);
    }

    private static boolean compareJsonNodes(JsonNode node1, JsonNode node2) {
        // 先判断节点类型是否一致
        if (node1.getNodeType() != node2.getNodeType()) {
            return false;
        }

        switch (node1.getNodeType()) {
            case OBJECT:
                // 对比对象的所有字段
                if (!node1.fieldNames().equals(node2.fieldNames())) {
                    return false;
                }
                for (String fieldName : node1.fieldNames()) {
                    if (!compareJsonNodes(node1.get(fieldName), node2.get(fieldName))) {
                        return false;
                    }
                }
                return true;
            case ARRAY:
                // 对比数组的每个元素(如果需要忽略顺序,这里可以先排序再对比)
                if (node1.size() != node2.size()) {
                    return false;
                }
                for (int i = 0; i < node1.size(); i++) {
                    if (!compareJsonNodes(node1.get(i), node2.get(i))) {
                        return false;
                    }
                }
                return true;
            case STRING:
                // 自定义字符串对比规则:处理带逗号的数字,去掉逗号再对比
                String val1 = node1.asText();
                String val2 = node2.asText();
                if (val1.matches("[\\d,]+") && val2.matches("[\\d,]+")) {
                    return val1.replace(",", "").equals(val2.replace(",", ""));
                }
                return val1.equals(val2);
            default:
                // 数字、布尔、null等直接对比
                return node1.equals(node2);
        }
    }
}

这个方案的好处是你可以完全自定义对比逻辑,比如针对你示例里的"Total Assets Consolidated"这种带逗号的数字字符串,自动处理后再对比,非常灵活。

方案3:反序列化为Java对象对比(最严谨,适合固定结构的JSON)

如果你的JSON结构是固定的(比如示例里的公司财务数据),可以定义对应的POJO类,把JSON反序列化为对象后,通过重写equals方法或者工具类来对比。

步骤:

  1. 定义POJO类(对应你的JSON结构):
import java.util.Objects;
import java.util.Map;

public class FinancialData {
    private Map<String, CompanyData> data;

    // 内部类对应公司财务数据
    public static class CompanyData {
        private String totalAssetsConsolidated;
        private String totalAssetsCompany;
        private String date;
        private String currency;
        private String totalRevenueConsolidated;
        private String totalRevenueCompany;
        private String rDate;

        // 自动生成Getter、Setter方法
        // 重写equals方法,自定义对比规则
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            CompanyData that = (CompanyData) o;
            // 处理带逗号的数字字符串
            return Objects.equals(totalAssetsConsolidated.replace(",", ""), that.totalAssetsConsolidated.replace(",", "")) &&
                    Objects.equals(totalAssetsCompany.replace(",", ""), that.totalAssetsCompany.replace(",", "")) &&
                    Objects.equals(date, that.date) &&
                    Objects.equals(currency, that.currency) &&
                    Objects.equals(totalRevenueConsolidated.replace(",", ""), that.totalRevenueConsolidated.replace(",", "")) &&
                    Objects.equals(totalRevenueCompany, that.totalRevenueCompany) &&
                    Objects.equals(rDate, that.rDate);
        }

        @Override
        public int hashCode() {
            return Objects.hash(totalAssetsConsolidated, totalAssetsCompany, date, currency, totalRevenueConsolidated, totalRevenueCompany, rDate);
        }
    }

    // 自动生成Getter、Setter、equals、hashCode方法
}
  1. 反序列化并对比:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

public class PojoJsonComparator {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws Exception {
        List<Map<String, FinancialData.CompanyData>> list1 = mapper.readValue(
                Files.readAllBytes(Paths.get("file1.json")),
                mapper.getTypeFactory().constructCollectionType(List.class,
                        mapper.getTypeFactory().constructMapType(Map.class, String.class, FinancialData.CompanyData.class)));
        
        List<Map<String, FinancialData.CompanyData>> list2 = mapper.readValue(
                Files.readAllBytes(Paths.get("file2.json")),
                mapper.getTypeFactory().constructCollectionType(List.class,
                        mapper.getTypeFactory().constructMapType(Map.class, String.class, FinancialData.CompanyData.class)));
        
        boolean isEqual = list1.equals(list2);
        System.out.println("两个JSON是否相等:" + isEqual);
    }
}

这个方案的优点是逻辑清晰,对比规则完全封装在POJO的equals方法里,适合长期维护的项目,能有效避免JSON结构变化带来的问题。

方案选择建议
  • 快速实现、无复杂规则需求:选方案1(JSONAssert/JsonUnit),代码最少,上手最快。
  • 需要自定义对比逻辑(比如处理特殊格式值):选方案2(Jackson树模型),灵活度最高。
  • JSON结构固定、长期维护:选方案3(POJO对比),最严谨,可读性最好。

内容的提问来源于stack exchange,提问作者Roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:01:43