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

使用GSON解析大JSON时,如何在HashSet添加Double时实现四舍五入?

高效解决GSON解析超大JSON时实时处理double值四舍五入的方案

嘿,针对你这个每次启动都要解析超大JSON(41万行、27.5MB)的需求,直接在GSON反序列化过程中完成四舍五入绝对是最优解——完全不用等解析完再遍历处理,既能省时间又能避免额外的内存开销。下面是具体的实现步骤:

1. 自定义TypeAdapter处理double数组的四舍五入

GSON允许我们为特定类型自定义序列化/反序列化逻辑,这里我们需要给double[]类型写一个TypeAdapter,在解析数组元素的同时就完成四舍五入操作:

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

public class DoubleArrayTypeAdapter extends TypeAdapter<double[]> {
    @Override
    public void write(JsonWriter out, double[] value) throws IOException {
        // 如果不需要序列化JSON,这个方法可以保持空实现;如果需要输出,按正常数组序列化即可
        out.beginArray();
        for (double d : value) {
            out.value(d);
        }
        out.endArray();
    }

    @Override
    public double[] read(JsonReader in) throws IOException {
        in.beginArray();
        List<Double> tempList = new ArrayList<>();
        while (in.hasNext()) {
            double originalValue = in.nextDouble();
            // 用BigDecimal实现精确的四舍五入到4位小数,避免浮点精度误差
            double roundedValue = new BigDecimal(originalValue)
                    .setScale(4, RoundingMode.HALF_UP)
                    .doubleValue();
            tempList.add(roundedValue);
        }
        in.endArray();
        // 将List转换为double数组返回
        double[] result = new double[tempList.size()];
        for (int i = 0; i < tempList.size(); i++) {
            result[i] = tempList.get(i);
        }
        return result;
    }
}

2. 调整实体类的内部类访问权限

GSON无法直接实例化非static的内部类,所以需要把你的Features、Geometry、Properties改成static内部类,否则解析时会报错:

import java.util.ArrayList;
import java.util.HashSet;

public class Contours {
    public String name = null;
    public String type = null;
    public ArrayList<Features> features = null;

    // 改为static内部类,让GSON可以正常实例化
    public static class Features {
        public String type = null;
        public Geometry geometry = null;
        public Properties properties = null;
    }

    public static class Geometry {
        public String type = null;
        public HashSet<double[]> coordinates = null;
    }

    public static class Properties {
        public String CONTOUR = null;
        public int OBJECTID;
        public String LAYER = null;
        public double ELEVATION;
    }
}

3. 注册TypeAdapter并流式解析JSON

为了避免一次性把整个27.5MB的JSON加载到内存,我们用Reader进行流式解析,同时把自定义的TypeAdapter注册到GsonBuilder中:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Main {
    public static void main(String[] args) {
        // 创建Gson实例并注册自定义TypeAdapter
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(double[].class, new DoubleArrayTypeAdapter())
                .create();

        // 用Reader流式读取文件,内存友好
        try (Reader reader = new FileReader("your-large-contour-file.json")) {
            Contours contours = gson.fromJson(reader, Contours.class);
            // 此时contours中所有coordinates里的double值已经是四舍五入到4位小数的结果了
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

为什么这个方案高效?

  • 实时处理:在反序列化每个double数组元素的瞬间就完成四舍五入,不需要解析完整个对象再遍历HashSet做二次处理,节省了额外的遍历时间。
  • 流式解析:用Reader读取文件,不会把整个大文件一次性加载到内存,避免内存溢出的同时也提升了解析速度。
  • 精确可靠:用BigDecimal处理四舍五入,避免了Math.round可能带来的浮点精度问题。

额外注意点

  • 如果你需要调整四舍五入的规则,可以修改RoundingMode的参数(比如HALF_DOWN、CEILING等)。
  • 如果你的JSON字段名和实体类成员名不一致,可以用@SerializedName注解来映射。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:45:52