• 一场由Integer引发的血案


    看过阿里巴巴开发手册的同学应该都会对Integer临界值127有点印象。

    原文中写的是:

    【强制】所有整型包装类对象之间值的比较,全部使用 equals 方法比较。

    说明:对于 Integer var = ? 在-128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生,

    会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都

    会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。

    没错,文中要求Integer对象比较的时候必须要用equals进行。

    然后很多同学对于为什么要这么干没什么感觉。对于IntegerCache.cache也没什么感觉。

    很多时候我们写的代码可能是这样的:

    Integer num = 127;
    
    if(num==128){
    	//...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这种情况下,我们拿Integer和一个数字比较的时候,是不会出什么问题。

    然后如果我们这样写

    Integer num1 = 127;
    num1++;
    Integer num2=  128;
    if (num1 == num2) {
        System.out.println(true);
    }
    else{
        System.out.println(false);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    神奇的事情发生了,num1和num2虽然都是128,但是他们并不相等。

    这是因为Integer的值如果是-128~127之间的时候,Integer并不会创建新的对象,而是从IntegerCache.cache中取出的,所以他们随便比较都没有问题。

    但是如果超出了这个范围,就不一样了。

    不信你可以试试下面的代码:

    Integer num1 = 127;
    Integer num2=  127;
    if (num1 == num2) {
        System.out.println(true);
    }
    else{
        System.out.println(false);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    =================================

    可惜的是工作中常常忘记了这一点,于是一场血案发生了。

    本人前段时间写的一段代码中有下面一段:

    String standardItemNameStr = sampleStandardItemList.stream()
      .filter(item -> item.getSampleId()==sample.getSampleId())
      .map(item -> item.getStandardItemName()).collect(Collectors.joining("、"));
    
    • 1
    • 2
    • 3

    系统刚刚上线的时候一切NICE,运行很正常。突然有一天出事了。客户跟反馈出BUG了。

    本该显示数据的地方,成了空值。

    自己在本地测试,一切OK。代码检测了十遍以上,没发现什么问题。

    把生产环境的数据DOWN下来一跑发现其中第二行item.getSampleId()的值是180,这时突然想起Integer的这个设定。二话不说,修改为下面的代码,一切恢复正常。

    String standardItemNameStr = sampleStandardItemList.stream()
        .filter(item -> item.getSampleId() .equals(sample.getSampleId()))
        .map(item -> item.getStandardItemName()).collect(Collectors.joining("、"));
    
    • 1
    • 2
    • 3

    这个问题虽然很简单,但还是很容易忽略的。由此也扩展思考了一下,去测试一下Double、Float包装类,并没有catch这类的设计思路。

    原因嘛应该也很简单,Integer是整数,很多时候我们用Integer的时候需要用到的值确实是比较小的,所以官方做个catch确实能起到提高执行效率的作用,而且这个缓存命中率还是比较高的,但是小数的主要用途是在小数方面,如果要做catch的话,那数量可就太多了。

    那么byte、short、long的包装类会不会也有catch的设计呢?在阅读的你不妨去写个测试程序,实验一下,然后回来在评论区告诉我一下。

    文中提到的阿里巴巴开发手册是很不错的书,我的另一篇文章把全套的阿里巴巴手册都收集起来了。有兴趣的同学可以去看一看:
    全套阿里巴巴开发手册和大神解读一起给你【2022年整理】

  • 相关阅读:
    学习C++第二十四课--成员函数模板,模板显示实例化与声明笔记
    学习笔记10--ASIL分解与冗余功能安全
    Python深度学习实战-基于class类搭建BP神经网络实现分类任务(附源码和实现效果)
    构建高可用的Redis服务(主从复制/哨兵/集群底层原理)
    <string.h>字符操作函数的实现(strcpy、strcat、mem)
    当你访问一个网页时,后台做了些什么?
    基于51单片机的花样流水灯设计
    C++:deque的概念以及stack和queue的模拟实现
    【Web通信】短轮询与长轮询(Long Polling)是什么?
    PLL锁相环倍频原理
  • 原文地址:https://blog.csdn.net/aley/article/details/127759724