Map存入的数据丢失类型任意
发现问题: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));
包装类型不能直接强转
-
// 强转会报如下错误 // class java.lang.Integer cannot be cast to class java.lang.Long Integer number = 10; // 这样的强转是不对的 Long number2 = (Long)number;
正确的转换方式
-
// 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);