新手求指导:Java中对比两个JSON文件的最优实现方案
Hey there! 刚接触JSON处理就碰到文件对比的需求很正常,我来给你梳理几个Java里处理这类需求的最优方案,结合你给出的嵌套JSON结构,应该能帮你快速上手~
方案1:用专门的JSON对比库(新手首选,省心高效)
这类库已经封装好了JSON对比的核心逻辑,不用自己写递归遍历,适合快速实现需求。推荐两个常用的:
JSONAssert
它是Apache生态下的工具库,支持灵活的对比规则(比如忽略字段顺序、忽略特定字段、模糊匹配值)。
步骤:
- 导入Maven依赖(如果用Maven的话):
<dependency> <groupId>org.skyscreamer</groupId> <artifactId>jsonassert</artifactId> <version>1.5.1</version> <scope>test</scope> <!-- 如果是业务代码可以去掉test scope --> </dependency>
- 读取两个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方法或者工具类来对比。
步骤:
- 定义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方法 }
- 反序列化并对比:
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
相关产品推荐
相关产品推荐

