使用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
相关产品推荐
相关产品推荐

