发现问题:Map存入的数据丢失类型
经常会使用 Map<String,Object> 来用于存储键值对的数据,由于我们使用 Object 类型来接收数字,但是有些时候会出现map并不知道我们传入的是 Long 还是 Integer 。也就是出现数据类型丢失的问题
接下来尝试复现bug:
- 准备一个Map<String,Object> ,并将Long对象存入
- 取出该Long对象,并用instance of 判断该对象类型
- 经过测试发现,正常的存取并不会出现该问题是正常的情况
- 尝试使用JSON将map序列化,转换后进行测试
- 测试发现,BUG成功复现了,数据类型丢失了,Long类型被降级为INT
测试的Demo代码如下:
package com.test;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.Map;
public class TestMain {
public static void main(String[] args) {
Map<String , Object> map = new HashMap<>();
Long dataLong = 123456L;
map.put("test",dataLong);
System.out.println(JSON.toJSONString(map));
Object test = map.get("test");
System.out.println("测试一下正常使用map,是否会导致存入了Long类型丢失转换为int:");
System.out.println(test instanceof Integer);
// ========
Object mapp = JSON.parse(JSON.toJSONString(map));
Map<String , Object> objectMap = (Map<String , Object>) mapp;
System.out.println(objectMap.toString());
Object objectTest = objectMap.get("test");
System.out.println("序列化存储map,是否会导致存入了Long类型丢失转换为int:");
System.out.println(objectTest instanceof Integer);
}
}
输出结果如下:
问题分析
不难发现,两次的map其实对应的JSON字符串样式的一直的,但是在从字符串转换为map时丢失了数据类型。
在进行转换时, Map 会根据我们传入的数值的大小来判断。也就是说如果你传入的数值的大小是在Integer.MIN_VALUE、 Integer.MAX_VALUE 之间,Map 就认为是 Integer 类型,如果超过了这个范围就认为是 Long 类型。
在实际开发中,还挺经常遇到这种情况的,开发初期理所当然的当成int类型处理和转换,会随着数据位数的增加在中后期就报错,到时候属于是隐性BUG了。
要解决也很简单,需要我们对数据类型的转换熟悉再熟悉。
问题解决
解决的思路很简单,就是确保无论map中提取到的对象是int还是long或其他,都要统一转换为我们想要的long类型,在做处理的时候就是**将这个对象也先序列化,再转换,**这样就可以确保数据类型不会丢失,达到预期。
// 不直接强转先用 Object 接收
Object number = map.get("number");
// 下面两种二选一
Long longNumber = Long.valueOf(number.toString());
Long longNumber = Long.valueOf(String.valueOf(number));
思考:数据类型转换
顺便整理复习一下知识点
1. 包装类型不能直接强转
// 强转会报如下错误
// class java.lang.Integer cannot be cast to class java.lang.Long
Integer number = 10;
// 这样的强转是不对的
Long number2 = (Long)number;
2. 正确的转换方式
基本数据类型之间的转换
// int 转 long
int a = 10;
long b = (long)a;
// long 转 int
long a = 10L;
int b = (int)a;
包装类型之间的转换
Integer a = 10;
Long b = a.longValue();
// Long 转 Integer
Long a = 10L;
Integer b = a.intValue();
// 或者
Long a = 10L;
Integer b = Math.toIntExact(a);
参考博客:原博写的不错