JSON 中 Long类型精度缺失的问题

JSON 中 Long类型精度缺失的问题

作者:Bright Xu

问题描述:后端返回的JSON字符串{"id": 130872882849357824, "name": "张三", "age": 22},前端通过user.id获取id时,id的值变成了130872882849357820,也就是说id的个位数精度缺失了。

问题原因:主要原因是前端将json字符串反序列化成对象时,将这个id转成了Number类型。JavaScriptNumber类型是IEEE 754双精度浮点型,在这个规定中能安全的表示整数的范围在 − ( 2 53 − 1 ) -(2^{53}-1) (2531) 2 53 − 1 2^{53}-1 2

<think>好的,我现在需要帮助用户解决他们提供的代码中的问题。首先,用户希望将使用JsonNode的代码改为使用JSONObject,但当前的实现存在错误。用户给出的代码片段中,他们尝试从JSONObject中获取字段"thedate"的值,并将其强制转换为Number类型,这显然有问题,因为getString返回的是String类型,不能直接转为Number。 首先,我需要理解代码的逻辑。用户的目标是过滤Kafka消息流,只保留那些"thedate"字段的值大于等于20250402L的记录。问题出在如何正确地从JSON字符串中解析出数值类型的时间戳。 接下来,我需要检查代码中的错误点。用户使用JSON.parseObject(log)将字符串解析为JSONObject,这没问题。然后,他们用getString("thedate")获取字段值,这里得到的是一个String类型的值。接着,他们尝试将这个String强制转换为Number,这会导致ClassCastException,因为String不是Number的子类。 接下来,我需要思考如何正确地将字符串转换为数值类型。可能的解决方案包括:首先检查该字段是否存在,然后确保其值确实是数值类型。或者,如果字段值存储为字符串形式的数字,需要先解析为Long。例如,如果"thedate"的值在JSON中是字符串格式的数字,如"20250402",那么需要将字符串转换为Long。但如果JSON中该字段本身就是数值类型,比如20250402,那么应该直接获取数值而不是字符串。 因此,代码中的错误在于错误地将String类型强制转换为Number。正确的做法应该是:如果"thedate"字段存储的是数值,应该使用getLong或先检查类型是否为Number再转换;如果存储的是字符串形式的数字,则需要先解析字符串为Long,并处理可能的格式异常。 此外,用户可能没有进行字段存在性检查,直接调用getString可能会导致JSONException,如果字段不存在的话。因此,需要添加has("thedate")检查来避免异常。 另一个需要注意的地方是Flink的类型推断。由于Lambda中使用泛型,可能需要使用returns来明确指定返回类型,否则Flink可能无法正确推断类型信息,导致运行时错误。 总结错误点: 1. 错误地将String强制转换为Number,导致类型转换异常。 2. 缺少字段存在性检查,可能导致异常。 3. 如果"thedate"是字符串形式的数字,需要解析转换;如果是数值类型,应直接获取数值。 4. 需要处理可能的解析异常,例如NumberFormatException。 5. Flink类型声明可能需要补充。 现在需要根据这些分析,提供修改后的代码,并解释每一步的修改原因,确保用户理解如何正确使用JSONObject来处理数值类型的字段,同时处理可能存在的异常情况,并确保类型安全和代码健壮性。</think>以下是针对该代码的 **错误分析和分步修正**,包含类型安全处理和异常防护: --- ### 原代码问题诊断 ```java String fieldValue = json.getString("thedate"); // 返回String类型 long timestamp = ((Number) fieldValue).longValue(); // 错误!String无法强制转为Number ``` **主要错误**: 通过 `getString("thedate")` 获取的字段值为 **字符串类型**,直接强制转换为 `Number` 会导致 `ClassCastException`。 --- ### 修正方案(分步实现) #### 场景假设 假设 `thedate` 字段在 JSON 中 **以数值形式存储**(如 `"thedate": 20250402`): ```java kafkaSourceDao.getStringMsg().filter( log -> { JSONObject json = JSON.parseObject(log); // 1. 检查字段存在性 if (!json.has("thedate")) return false; // 2. 直接获取数值类型(非字符串) Object value = json.get("thedate"); if (!(value instanceof Number)) return false; long timestamp = ((Number) value).longValue(); return timestamp >= 20250402L; } ).returns(Types.STRING); // 根据输入流类型声明返回类型 ``` #### 场景假设 假设 `thedate` 字段在 JSON 中 **以字符串形式存储数值**(如 `"thedate": "20250402"`): ```java kafkaSourceDao.getStringMsg().filter( log -> { JSONObject json = JSON.parseObject(log); // 1. 检查字段存在性 if (!json.has("thedate")) return false; // 2. 读取字符串并尝试转为数值 String strValue = json.getString("thedate"); try { long timestamp = Long.parseLong(strValue); return timestamp >= 20250402L; } catch (NumberFormatException e) { return false; // 非数字字符串直接过滤 } } ).returns(Types.STRING); ``` --- ### 修正对比表(关键改动说明) | 原代码问题 | 修正方案 | |------------------------|--------------------------------------------------------------------------| | 错误类型转换 | 根据字段实际存储类型选择 `get()` 或 `getString()` + 显式类型检查/解析 | | 缺少字段存在性检查 | 添加 `json.has("thedate")` 前置判断 | | 未处理非法格式数据 | 添加 `try-catch` 或 `instanceof` 防御性检查 | | Flink 类型声明缺失 | 追加 `.returns(...)` 声明输出类型 | --- ### 完整可运行代码(数值型字段场景) ```java // 依赖需包含 org.json 库 DataStream<String> filteredStream = kafkaSourceDao.getStringMsg() .filter(log -> { try { JSONObject json = JSON.parseObject(log); // 防御性检查三部曲 if (!json.has("thedate")) return false; Object value = json.get("thedate"); if (!(value instanceof Number)) return false; // 安全转换 long timestamp = ((Number) value).longValue(); return timestamp >= 20250402L; } catch (Exception e) { return false; // 捕获 JSON 解析异常等 } }) .returns(Types.STRING); // 声明输出类型为字符串流 ``` --- ### 关键修改点详解 1. **防御性类型检查** 使用 `Object value = json.get("thedate")` 获取原始值,通过 `instanceof Number` 确保字段为数值类型: ```java if (!(value instanceof Number)) return false; // 过滤非数值类型 ``` 2. **异常处理增强** 在 `JSON.parseObject(log)` 外层添加 `try-catch`,防止非法 JSON 格式导致任务崩溃: ```java try { // ... 解析逻辑 } catch (Exception e) { return false; } ``` 3. **Flink 类型系统适配** 通过 `.returns(Types.STRING)` 明确声明输出流类型,避免类型擦除导致的运行时错误。 --- ### 注意事项 1. **数值精度问题** 如果字段值可能是 `Double` 或 `Float`,需注意强制转换为 `long` 时的精度损失: ```java double d = json.getDouble("thedate"); long timestamp = (long) d; // 可能丢失小数部分 ``` 2. **性能优化建议** 高频调用时建议将 `JSON.parseObject` 替换为更高效的解析器(如 Jackson),或预编译 JSON 结构。 3. **字段路径嵌套** 如果 `thedate` 字段在嵌套结构中,需使用 `getJSONObject().get()` 链式访问: ```java JSONObject nested = json.getJSONObject("parent"); if (nested != null && nested.has("thedate")) { // ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值