【问题标题】:Convert list to json file将列表转换为 json 文件
【发布时间】:2016-11-26 17:18:17
【问题描述】:

我有一个流列表,想转换成 json 并保存为 json 文件。

代码如下:

stream
          .map(e -> e.split(";"))
          .map(e -> {
            Industry in = new Industry();
            in.code = Integer.parseInt(e[0]);
            in.description = e[1];
            return in;
          })
          .collect(Collectors.toList())
          .forEach(e -> System.out.println(e.code));

如何转换成json并保存为文件?

谢谢

【问题讨论】:

  • 使用您喜欢的 JSON 编组器/映射器。有几十个。杰克逊可能是最受欢迎的。谷歌搜索“如何将 Java 对象转换为 JSON”应该会返回几十个结果。
  • 您的代码与stream .map(e -> e.split(";")) .forEach(e-> System.out.println(e[0])); 一样是一种复杂的操作方式,其他一切都只是浪费资源。但最值得注意的是,它不会产生任何可以转换为 json 的东西。那么有什么意义呢?

标签: java json collections java-stream


【解决方案1】:

我写这个答案只是为了表示类内序列化比使用第三方序列化库(如 Jackson)要快得多。

对于快速序列化,尤其是在分布式计算和繁重的跨应用程序通信的情况下,为此目的开发接口或基类在性能方面是明智的。这将与以下代码相似,但不一定相同:

public abstract class JsonCompatible {
    public abstract String jasonSerialize();
    public abstract void jasonDeserialize(String obj);
    protected String[] breakAsJson(String obj){
        return obj.substring(1, obj.length()-2).replace("\"", "").split(",");       
    } 
}

要序列化的数据模型或类可以实现接口或示例抽象类。为了同时解决提问者的问题并提供解决方案,我为Industry 类开发了一个示例。

public class Industry extends JsonCompatible {
    private String id, description;
    private int code;

    public Industry(String id, String description, int code) {
        this.id = id;
        this.description = description;
        this.code = code;
    }
    public Industry(String id, String description, String code) {
        this.id = id;
        this.description = description;
        this.code = Integer.parseInt(code);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }
    public void setCode(String code) {
        this.code = Integer.parseInt(code);
    }    
    public Industry() {
    }

    @Override
    public String jasonSerialize() {
        return String.format("{\"Id\":\"%s\", \"Code\":\"%d\", \"Description\":\"%s\"}", id, code, description);
    }

    @Override
    public void jasonDeserialize(String obj) {
        for(String i : breakAsJson(obj)){
            String[] expand = i.split(":");
            if(expand.length > 1){
                expand[0] = expand[0].trim();
                if(expand[0].equals("Id")){
                    id = expand[1];
                }
                else if (expand[0].equals("Code")){
                    setCode(expand[1]);
                }
                else if(expand[0].equals("Description")){
                    description = expand[1];
                }
            }
        }
    }

}

如示例代码所示,Industry 类派生自 JsonCopatible。此时,我们可以开发一个数组序列化器来序列化Industry 对象的集合,并且序列化它比Jackson 执行的速度快得多,如下所示。

public class JsonArray<T extends JsonCompatible> {
    private List<T> obj;
    private String namespace = "Default";
    public JsonArray(List<T> obj) {
        this.obj = obj;
    }

    public JsonArray(List<T> obj, String namespace) {
        this.obj = obj;
        this.namespace = namespace;
    }

    public String getJasonArray(){
        StringBuilder sb = new StringBuilder();
        sb.append("{\"").append(namespace).append("\": [");
        List<String> elements = obj.stream().map(x-> x.jasonSerialize()).collect(Collectors.toList());
        int size = elements.size();
        for(int i = 0; i < size; i++){
            sb.append(elements.get(i));
            if(i < size - 1){
                sb.append(",");
            }
        }
        sb.append("]}");
        return sb.toString();
    }
}

很明显,这只是这种方法的一个例子,它必须根据项目/询问者的需要和要求进行定制。由于数组序列化以通用方式工作,因此不会涉及任何冗余代码,并且由于这不依赖于反射(Jackson 所依赖的),因此效率更高。

【讨论】:

    【解决方案2】:

    我们使用jackson将对象转换成JSON

            var objectMapper = new ObjectMapper();
    
            var data = stream
              .map(e -> e.split(";"))
              .map(e -> {
                Industry in = new Industry();
                in.code = Integer.parseInt(e[0]);
                in.description = e[1];
                return in;
              })
              .collect(Collectors.toList());
    
             var outputJsonFile = new FileOutputStream("data.json");
             objectMapper.writeValue(outputJsonFile, e);
    

    注意:var 是在 Java 10 中引入的。以上代码适用于 Java 11+(稳定版本)。

    有关Jackson的更多信息: http://tutorials.jenkov.com/java-json/jackson-objectmapper.html

    【讨论】:

    • 逐个序列化每个对象并不是一个好主意。为什么不直接序列化整个列表,从而得到一个有效的 JSON 文件呢?特别是因为这实际上只将最后一个对象写入文件。并且永远不会关闭流。
    • @JBNizet:Not really a good idea to serialize each object one by one。我认为如果你为此目的在你的类中定义一个方法来做到这一点是一个非常好的主意,因为这将非常快。例如,当您需要克隆列表中的对象时。这样做的原因是:不需要反射。
    • @Transcendent 如果不使用反射,您认为 Jackson 如何将它一无所知的对象转换为 JSON?此外,这里的目标不是克隆对象。它是将对象列表写入文件。
    • @Transcendent:我看不出您的评论如何以任何方式解决同时处理单个项目或整个列表之间的差异。如果您想只克隆 对象并关心性能,那么写入文件或转换为介于两者之间的 JSON 都不是建设性的。如果要克隆对象,只需克隆它们。
    • @Holger:正如我所解释的,您已经开发了一个接口,它有两种方法,例如String Serialize(), and void DeSerialize(T obj)。您的数据模型必须实现该接口,然后您可以开发一个泛型方法,其泛型类型例如为&lt;T extends Serializable&gt;。然后您可以有效地将对象转换为 JSON,反之亦然(甚至是 XML)。如果你有兴趣,我可以给你写代码作为答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 2020-04-01
    • 2021-08-27
    • 2017-11-30
    • 1970-01-01
    相关资源
    最近更新 更多