今天要记录的最近上线的一个bug,本身很简单,修复的也很快但是确实不应该发生。
首先代码里是通过redisson从redis里取出一个关于用户的缓存,用户缓存信息使用map结构存储,因为value值相对变化比较多,有int型的userid或者string型的username等等,代码中为了适应不同类型的value,将map定义为map<String, Object>,通过Object userId = map.get(“userId”)获取用户id,但是在后续使用userId的时候却偷懒了,想当然的认为userId这种字段属于比较“正规”的字段,所以后续代码中调用其它方法需要传参userId的时候顺手就写了 (Integer)userId进行强转,结果上线之后立刻有业务方反应接口返回异常,查log后可以很清晰的看到都是String到Integer的CastException,至于为什么userId会是字符串,这种数据本身是否合理那就是内部业务和设计的问题了,这个不过多讨论,但是写代码的时候确实不应该想当然的直接强转,毕竟这个操作本身就有风险,尤其是要强转成类似于Integer这种有格式和范围要求的类型时,直接选择信任数据来源不做判断进行强转本身就是一种不负责任的代码。
当时的解决方案是我们系统中有自己的工具类,实现了从String到Integer的转换,但是差点儿因为粗心再次出bug,好在组内有经验的同学提前告知了问题,先看一下我们工具类的代码:
public static int getInt(Object get) {
if (get == null) {
return 0;
} else {
String s = get.toString();
return NumberHelper.isInt(s) ? Integer.parseInt(s) : 0;
}
}
可以看到如果传入的字符串为空,那我们的工具类其实会返回0,但是在我的代码中null和0完全是两个不同的概念,所以当返回0之后还需要再次额外处理才可以,暂且不说工具类这样设计是否合理,看来以后在使用别人封装的代码之前也需要好好阅读代码,因为人和人的想法是不同的,尽量减少这种错误的bug数量。
这两件事给我的经验总结就是:作为一名程序员,任何时候都不应该盲目相信别人提供给你的东西,不管是自称可靠的数据还是一个你刚好需要的封装方法,一定要记得自己多看看,多判断一下,这样才能掌控自己的代码