• 看我在Map<String, String>集合中,存入Integer类型数据



    一、前情提要

    前几天测试给我提了一个缺陷,提示类型转化报错,可是我怎么看对应的代码都想不明白问题在哪里


    1、缺陷背景

    将模型大致抽象一下,就是其他同事将前台的数据放入到一个map中,然后再把这个map转为json字符串传给后台,紧接着再把这个json字符串反序列化为一个map对象,最后把这个map对象传递给我。


    2、报错提示如下:

    光看报错提示,其实还是很开心的,这明显是一个类型转化异常,那必然是我将一个Integer类型的数字转化为一个String类型的字符串导致的,继续往下看


    3、代码报错的位置

    定位到报错的位置是下面的方法,然后我陷入了沉思,String转Integer?你这是哪门子的类型转化异常?我这不是两个String?


    4、该方法只是一个简单的判空方法





    二、寻找问题

    1、捞日志看接收参数

    心里窃喜,还好我把接收的参数打印在了日志里面。结果发现我在打日志的时候是直接传的map,并没有对其进行自定义的序列化,以至于我无法看到数据对应的类型(后文会说明,这个数据类型很重要),下次自己得记住要序列化


    2、观察前台传给后台的参数

    无奈,我只能前台看对应的参数情况,最终在前台的参数里面找到了它。发现一个参数不像是字符串


    3、再次执行判断方法

    然后我用数字类型的参数去执行StringUtils.isNotBlank()方法,只能说这个错误对味了。

    但是新问题来了:

    1. 如果直接是数字编译通不过呀!
    2. 就算是Object类型的参数,我这里还需要强转,可是我的代码没有强转呀!
    3. 还有就是我报错的方法的参数泛型为Map<String,String>,泛型限定为String类后都不能接收Integer类型的参数呀!真的吗?

    4、于是在阅读了同事的代码之后,再次定位问题

    同事的工作其实就是把前台给的json字符串,反序列化为一个Map<String,String>的集合中。那么问题只能是在这个反序列化了,明明传进去的时候都还有数字,怎么出来就没有数字了?





    三、验证问题

    1、自己反序列化测试

    模拟全过程代码

    public class Map泛型兼容 {
    	public static void main(String[] args) {
    		// 模拟前台的传给后台的数据
    		Map<String, Object> map = new HashMap<>();
    		map.put("key1", 1);
    		map.put("key2", "a");
    
    		String jsonStr = "";
    		jsonStr = JSON.toJSONString(map);
    		// 传给后台的json字符串
    		System.out.println(jsonStr);
    
    		// 对字符串进行反序列化
    		Map<String, String> params = JSON.parseObject(jsonStr, HashMap.class);
    
    		for (Map.Entry<String, String> entry : params.entrySet()) {
    			if (entry.getValue() instanceof String) {
    			} else {
    				System.out.println("不是字符串类型");
    			}
    			System.out.println(entry.getValue());
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    我们惊奇的发现,居然不报错,他居然不报错,他居然不报错,Integer的转化为String居然没问题,并且最终拿到数据的时候也还是Integer类型,我直接好家伙。

    然后我就联想了一下json反序列化是通过反射完成的。



    2、反射再验证

    它居然还真可以,我使用反射向Map<String,String>的对象中添加数据,然后遍历该map对象,但是却发现其value是一个Integer类型。

    那么一切就说的通了

    验证代码:

    public class TestReflect {
    	public static void main(String[] args) throws Exception {
    		Map<String, String> map = new HashMap<>();
    
    		Method put = map.getClass().getMethod("put", Object.class, Object.class);
    		put.invoke(map, "key1", 1);
    		put.invoke(map, "key2", "value2");
    		System.out.println(JSON.toJSON(map));
    
    		for (Map.Entry<String, String> entry : map.entrySet()) {
    			if (entry.getValue() instanceof String) {
    			} else {
    				System.out.println("该key是其他类型:" + entry.getValue().getClass());
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17



    3、结论

    最终的结论就是,同事在把前台的所有参数传到后台的时候,里面包含了一个value为Integer类型的数据,那类比就是放到了一个Map<String,Object>的map集合中,在对该map进行序列化后,就变成了一个普通的json字符串。

    问题的关键就在于反序列这个位置,在对该json字符串反序列化的时候,就出现了问题。但是这个属于运行时异常了。因为我们的json字符串里面含有Integer类型的参数,但是反序列化的对象却是一个String类型,根据前文的演示,在利用反射进行赋值的时候,并不会报错,以至于一切风平浪静。

    但当在我们在使用对应参数的时候,问题就来了,因为我们只认反序列化回的String类型的map,但是实际拿到的却是Integer,以至于引发了后续的错误。


    那我们应该如何使用呢?


    在我看来我们如果无法明确参数是否可能存在多种类型,可以使用Object类型的map接收反序列出来的集合数据,在获取对应参数的时候也不要使用强转的形式,而是使用更加友好的String.valueOf获取对应的内容(其底层就是调用包装类型的toString方法)

  • 相关阅读:
    redis基本工具类编写
    【精讲】vue框架 利用脚手架实现购物车(含添加、删除、存储、清空数据、全选or单选、tap栏切换)内含详细注释
    Unity-Input System新输入系统插件学习
    蓝牙Mesh系统开发四 ble mesh网关节点管理
    HTML网页设计制作——初音动漫(6页) dreamweaver作业静态HTML网页设计模板
    微软(TTS)文本转语音服务API实现
    Unity中 Start和Awake的区别
    【论文精读7】MVSNet系列论文详解-PVA-MVSNet
    @Autowired注解以及失效几个原因
    每日五道java面试题之springMVC篇(三)
  • 原文地址:https://blog.csdn.net/qq_44377709/article/details/125436811