一场由Java中Integer引发的踩坑实战

 更新时间:2022年11月10日 11:14:00   作者:我是老姚  
Java中的数据类型分为基本数据类型和复杂数据类型int是前者而integer是后者(也就是一个类),下面这篇文章主要给大家介绍了关于由Java中Integer引发的踩坑实战,需要的朋友可以参考下

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

原文中写的是:

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

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

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

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

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

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

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

Integer num = 127;
if(num==128){
	//...
}

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

然后如果我们这样写

Integer num1 = 127;
num1++;
Integer num2=  128;
if (num1 == num2) {
    System.out.println(true);
}
else{
    System.out.println(false);
}

神奇的事情发生了,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);
}

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

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

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

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

系统刚刚上线的时候一切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("、"));

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

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

那么byte、short、long的包装类会不会也有catch的设计呢?

补充:Java Integer比较中的那些坑

前几天同事偶然遇到的一个问题,在list中查询出重复的值,留下第一个,其余删除。

ArrayList<Integer> a//a中装有要操作的数据,都是数字
for(int i;i<a.size();i++){
    //....遍历
    for(int j=i;j<a.size();j++){
        if(a.get(i)==a.get(j)){
        a.remove(j);
        }
    }
}

然后喜闻乐见的程序出问题了:程序无法将相同的值除第一个外删除掉。说起来这也是一个比较基础性的问题。

int为基本类型,Integer类型为基本包装类型。因而可以将Integer当做一个对象来理解,所以在上面的代码示例中,用==来比较2个对象的引用无疑就是在搞笑了,地址都不一样,怎么可能返回true。

但是这里存在着一些坑,就是Integer有时候用==比较是可以得到true的(值相同),原因如下:

在-128至127之间的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象。

所以推荐都使用equals比较。

附上int类型自动装箱为Integer时的源代码(IntegerCache.low为-128)

public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

这里还牵涉到了一点,就是这里为什么不直接用int类型呢?这是因为ArrayList中只接受Object对象,实际情况如下:

ArrayList al=new ArrayList();
int n=40;
Integer nI=new Integer(n);
al.add(n);//不可以
al.add(nI);//可以

总结

到此这篇关于一场由Java中Integer引发的踩坑实战的文章就介绍到这了,更多相关Java中Integer踩坑内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java算法题解LeetCode35复杂链表的复制实例

    java算法题解LeetCode35复杂链表的复制实例

    这篇文章主要为大家介绍了java算法题解LeetCode35复杂链表的复制实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • spring boot教程之建立第一个HelloWorld

    spring boot教程之建立第一个HelloWorld

    这篇文章主要介绍了spring boot教程之建立第一个HelloWorld的相关资料,需要的朋友可以参考下
    2022-08-08
  • multi-catch和try-catch异常处理知识点详解

    multi-catch和try-catch异常处理知识点详解

    在本篇文章里我们给大家分享了一篇关于multi-catch和try-catch异常处理知识点内容,有需要的朋友们可以参考学习下。
    2019-11-11
  • 详解Java-Jackson使用

    详解Java-Jackson使用

    这篇文章主要介绍了Java-Jackson使用详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • Java设计模式之Strategy模式

    Java设计模式之Strategy模式

    Strategy模式即策略模式,就是将一个算法的不同实现封装成一个个单独的类,这些类实现同一个接口,使用者直接使用该接口来访问具体的算法。这个样子,使用者就可以使用不同的算法来实现业务逻辑了。
    2016-07-07
  • 详解java中String值为空字符串与null的判断方法

    详解java中String值为空字符串与null的判断方法

    这篇文章主要介绍了详解java中String值为空字符串与null的判断方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 如何使用Spring Boot实现自定义Spring Boot插件

    如何使用Spring Boot实现自定义Spring Boot插件

    在本文中,我们介绍了如何使用 Spring Boot 实现自定义插件,使用自定义插件可以帮助我们快速地添加一些额外的功能,提高系统的可扩展性和可维护性,感兴趣的朋友跟随小编一起看看吧
    2023-06-06
  • java关于持久层面试题目整理

    java关于持久层面试题目整理

    在本篇文章里小编给大家分享的是一篇关于java关于持久层面试题目整理内容,需要的朋友们可以学习下。
    2020-03-03
  • Java数据结构之集合框架与常用算法详解

    Java数据结构之集合框架与常用算法详解

    Java集合框架是Java中常用的数据结构库,包括List、Set、Map等多种数据结构,支持快速的元素添加、删除、查找等操作,可以用于解决各种实际问题。Java中也有多种常用算法,如排序、查找、递归等,在数据处理和分析中有广泛应用
    2023-04-04
  • Mybatis关联映射举例详解

    Mybatis关联映射举例详解

    关联关系是面向对象分析、面向对象设计最终的思想,Mybatis完全可以理解这种关联关系,如果关系得当,Mybatis的关联映射将可以大大简化持久层数据的访问
    2022-07-07

最新评论