实际字符串
String dataStr = "{\n" +
" \"data\": [\n" +
" {\n" +
" \"data\": [\n" +
" {\n" +
" \"areaId\": 1,\n" +
" \"H\": 2,\n" +
" \"S\": 3,\n" +
" \"Q\": 12\n" +
" },\n" +
" {\n" +
" \"H\": 1,\n" +
" \"S\": 3,\n" +
" \"Q\": 12,\n" +
" \"areaId\": 2\n" +
" }\n" +
" ],\n" +
" \"time\": \"2024-01-01 00:00:00\"\n" +
" },{\t \"data\": [\n" +
" {\n" +
" \"areaId\": 1,\n" +
" \"H\": 122,\n" +
" \"S\": 3,\n" +
" \"Q\": 121\n" +
" },\n" +
" {\n" +
" \"H\": 121,\n" +
" \"S\": 3,\n" +
" \"Q\": 122,\n" +
" \"areaId\": 2\n" +
" }\n" +
" ],\n" +
" \"time\": \"2024-01-01 02:00:00\"}\n" +
" ],\n" +
" \"state\": true\n" +
"}";
实际使用过程中这个dataStr.length()长度达到了1.5亿左右,转换成一份txt文档,140+M,note打不开了,网上json格式化工具也格式化不了,测试过程只能使用读入文件的方式测试不同方式转化成实体类的效率。
比较常用的方法
是直接用 com.alibaba.fastjson 下的JSONObject.parseObject将JSON字符串反序列化为Java对象的过程
MyObject response = JSONObject.parseObject(dataStr, MyObject .class);
这样做简单便捷,但是有一个问题是当这个字符串dataStr很长很大的时候,这样做容易引起oom导致程序奔溃,或者响应时间太长,对及时性要求高的不适用。
以下是改写优化
版本一:使用readValue反序列化为Person
对象,使用中发现它的效率比JSONObject.parseObject好一些,但是长文本也是捉襟见肘。
ObjectMapper objectMapper = new ObjectMapper();
Person person = objectMapper.readValue(json, Person.class);
版本二:将字符串解析为JsonNode
对象,根据自己的需要获取对应的节点数据,它的效率比readValue更好些,但是比较麻烦,需要自己一个个节点取数据。
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode= objectMapper.readTree(json);
if (rootNode.has("data")) {
// 遍历对应的对象取数据
ArrayList<ModelArea> modelList = new ArrayList<>();
JsonNode dataArrayNode = rootNode.get("data");
for (JsonNode timeDataNode : dataArrayNode) {
// ...
}
}
这种方法足以应付常规几M甚至即使M的json文件了,但是文件再大一些,又oom了
版本三:节点很多的情况增加流式处理,使用了elements()
方法来获取JSON数组的元素流,并使用forEachRemaining()
方法来遍历元素
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode rootNode = objectMapper.readTree(dataStr);
List<ModelArea> timeDataList = new ArrayList<>();
rootNode.get("data").elements().forEachRemaining(timeDataNode -> {
// 第一层处理
timeDataNode.get("data").elements().forEachRemaining(gridDataNode -> {
// 第二层处理
});
});
}