简体   繁体   English

如何使用Jackson在Java中高效地从JSON文件中读取数据?

[英]How do I read a data from a JSON file with high efficiency in Java with Jackson?

I store all static data in the JSON file. 我将所有静态数据存储在JSON文件中。 This JSON file has up to 1000 rows. JSON文件最多可包含1000行。 How to get the desired data without storing all rows as ArrayList ? 如何在不将所有行存储为ArrayList情况下获取所需的数据?

My code, I'm using right now and I want to increase its efficiency. 我的代码,我现在正在使用,我想提高其效率。

List<Colors> colorsList = new ObjectMapper().readValue(resource.getFile(), new TypeReference<Colors>() {});
    for(int i=0; i<colorsList.size(); i++){
        if(colorsList.get(i).getColor.equals("Blue")){
            return colorsList.get(i).getCode();
        }
    }

Is it possible? 可能吗? My goal is to increase efficiency without using ArrayList . 我的目标是在不使用ArrayList情况下提高效率。 Is there a way to make the code like this? 有没有办法像这样编写代码?

Colors colors = new ObjectMapper().readValue(..."Blue"...);  
return colors.getCode();

Resource.json Resource.json

[
...
  {
    "color":"Blue",
    "code":["012","0324","15478","7412"]
  },
  {
    "color":"Red",
    "code":["145","001","1","7879","123984","89"]
  },
  {
    "color":"White",
    "code":["7","11","89","404"]
  }
...
]

Colors.java Colors.java

class Colors {

    private String color;
    private List<String> code;

    public Colors() {
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public List<String> getCode() {
        return code;
    }

    public void setCode(List<String> code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return "Colors{" +
                "color='" + color + '\'' +
                ", code=" + code +
                '}';
    }
}

Creating POJO classes in this case is a wasting because we do not use the whole result List<Colors> but only one internal property. 在这种情况下创建POJO类很浪费,因为我们不使用整个结果List<Colors>而只使用一个内部属性。 To avoid this we can use native JsonNode and ArrayNode data types. 为了避免这种情况,我们可以使用本地JsonNodeArrayNode数据类型。 We can read JSON using readTree method, iterate over array, find given object and finally convert internal code array. 我们可以使用readTree方法读取JSON ,遍历数组,找到给定的对象,最后转换内部code数组。 It could look like below: 它可能如下所示:

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

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();

        ArrayNode rootArray = (ArrayNode) mapper.readTree(jsonFile);
        int size = rootArray.size();

        for (int i = 0; i < size; i++) {
            JsonNode jsonNode = rootArray.get(i);
            if (jsonNode.get("color").asText().equals("Blue")) {
                Iterator<JsonNode> codesIterator = jsonNode.get("code").elements();
                List<String> codes = new ArrayList<>();
                codesIterator.forEachRemaining(n -> codes.add(n.asText()));

                System.out.println(codes);
                break;
            }
        }
    }
}

Above code prints: 上面的代码打印:

[012, 0324, 15478, 7412]

Downside of this solution is we load the whole JSON to memory which could be a problem for us. 该解决方案的缺点是我们将整个JSON加载到内存中,这可能对我们来说是个问题。 Let's try to use Streaming API to do that. 让我们尝试使用Streaming API来做到这一点。 It is a bit difficult to use and you must know how your JSON payload is constructed but it is the fastest way to get code array using Jackson . 使用它有点困难,您必须知道JSON有效负载的构造方式,但这是使用Jackson来获取code数组的最快方法。 Below implementation is naive and does not handle all possibilities so you should not rely on it: 下面的实现是幼稚的,不能处理所有可能性,因此您不应依赖它:

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        System.out.println(getBlueCodes(jsonFile));
    }

    private static List<String> getBlueCodes(File jsonFile) throws IOException {
        try (JsonParser parser = new JsonFactory().createParser(jsonFile)) {
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String fieldName = parser.getCurrentName();
                // Find color property
                if ("color".equals(fieldName)) {
                    parser.nextToken();
                    // Find Blue color
                    if (parser.getText().equals("Blue")) {
                        // skip everything until start of the array
                        while (parser.nextToken() != JsonToken.START_ARRAY) ;

                        List<String> codes = new ArrayList<>();
                        while (parser.nextToken() != JsonToken.END_ARRAY) {
                            codes.add(parser.getText());
                        }
                        return codes;
                    } else {
                        // skip current object because it is not `Blue`
                        while (parser.nextToken() != JsonToken.END_OBJECT) ;
                    }
                }
            }
        }

        return Collections.emptyList();
    }
}

Above code prints: 上面的代码打印:

[012, 0324, 15478, 7412]

At the end I need to mention about JsonPath solution which also can be good if you can use other library: 最后,我需要提及有关JsonPath解决方案的信息,如果您可以使用其他库,那么它也可能很好:

import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;

import java.io.File;
import java.util.List;
import java.util.stream.Collectors;

public class JsonPathApp {
    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        JSONArray array = JsonPath.read(jsonFile, "$[?(@.color == 'Blue')].code");
        JSONArray jsonCodes = (JSONArray)array.get(0);
        List<String> codes = jsonCodes.stream()
                .map(Object::toString).collect(Collectors.toList());

        System.out.println(codes);
    }
}

Above code prints: 上面的代码打印:

[012, 0324, 15478, 7412]

You can use DSM stream parsing library for memory, CPU efficiency and fast development . 您可以将DSM 解析库用于内存,CPU效率和快速开发 DSM uses YAML based mapping file and reads the whole data only once . DSM使用基于YAML的映射文件,并且读取一次整个数据

Here is the solution of your question: 这是您的问题的解决方案:

Mapping File: 映射文件:

params:
   colorsToFilter: ['Blue','Red']  # parameteres can be passed programmatically
result:
   type: array
   path: /.*colors  # path is regex
   filter: params.colorsToFilter.contains(self.data.color)  # select only color that exist in colorsToFilter list
   fields:
      color: 
      code:
         type: array

Usage of DSM to parse json: DSM解析json的用法:

DSM dsm = new DSMBuilder(new File("path/maping.yaml")).create(Colors.class);
List<Colors> object = (List<Colors>) dsm.toObject(jsonData);

System.out.println(object);

Output: 输出:

[Colors{color='Blue', code=[012, 0324, 15478, 7412]}, Colors{color='Red', code=[145, 001, 1, 7879, 123984, 89]}]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM