一场由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踩坑内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中关于int和Integer的区别详解

    1.Java 中的数据类型分为基本数据类型和复杂数据类型 int是前者,integer 是后者(也就是一个类). 2.初始化时 复制代码 代码如下: int i = 1; Integer i = new Integer(1);   // (要把integer 当做一个类看) int 是基本数据类型(面向过程留下的痕迹,不过是对Java的有益补充) Integer 是一个类,是int的扩展,定义了很多的转换方法 类似的还有:float Float.double Double.string Stri

  • 浅析java中Integer传参方式的问题

    Java本身都是值传递式的调用,对于对象传递的是地址值.给地址值重新赋值等于重新指向,不会影响外层.而且这里Integer对象也有特殊性.其实现上可能类似 复制代码 代码如下: class Integer{final int value; //一旦赋值,就不能改变.} 这就出现:调用时传的地址值不能改变外层+对象本身又不能改变.导致这个值没法改变 解决方案很多1.java风格就是,单个值用返回值.return i; 外面再i=foo();赋值:多个值用数组或对象.2.传递自己的封装类.class

  • 详解Java中int和Integer的区别

    基本数据类型和引用类型 Java是面向对象的编程语言,一切都是对象,但是为了编程的方便还是引入了基本数据类型,为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换,对应如下: 原始类型:boolean,char,byte,short,int,long,float,double 包装类型:Boolean,Character,Byte

  • Java int与integer的对比区别

    Java int与 integer区别: int与integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象 1.Java 中的数据类型分为基本数据类型和复杂数据类型 int 是前者而integer 是后者(也就是一个类):因此在类进行初始化时int类的变量初始为0.而Integer的变量则初始化为null. 2.初始化时: int i =1:Integer i= new Integer(1);(要把int

  • Java Integer如何获取第一位和最后一位,并截取

    目录 Integer获取第一位和最后一位并截取 场景 求Integer位数的巧妙方法 Integer获取第一位和最后一位并截取 场景 获取 5,10,15,25,30; 判断尾数为5的进入判断 public static void main(String[] args) {         String str = "数据测试,自定义字段";         //判断第一个字符是否为"数"         if (str.startsWith("数&quo

  • 关于Java中你所不知道的Integer详解

    前言 本文主要给大家介绍了关于Java中Integer的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 实参形参 前些天看到朋友圈分享了一片文章<Java函数的传参机制--你真的了解吗?> 有些触发,之前也研究过Java的Integer,所以写下本文,希望对你有所帮助. 交换 首先来看一个示例. 请用Java完成swap函数,交换两个整数类型的值. public static void test() throws Exception { Integer a = 1,

  • Java中Integer两种转int方法比较

    方法一: Integer.parseInt(); 返回的是一个 int 的值. 方法二: new Integer.valueof(); 返回的是 Integer 的对象. new Integer.valueof().intValue(); 返回的也是一个 int 的值. 笔试应用例题: 设有下面两个赋值语句: a = Integer.parseInt("123"); b = Integer.valueOf("123").intValue(); 下述说法正确的是( 

  • Java中int和Integer的区别

    目录 1.基本数据类型 2.包装类及其作用 2.1包装类的作用 3.int 和 Integer 的区别 4.总结 重要说明:本篇为博主<面试题精选-基础篇>系列中的一篇,查看系列面试文章请关注我. Gitee 开源地址:gitee.com/mydb/interv- nJava 是一种强数据类型的语言,因此所有的属性必须有一个数据类型.就像麦德龙超市一样,想要进去购物,先要有一个会员卡才行(刷卡入内).​ PS:Java 10 有了局部变量类型推导,可以使用 var 来替代某个具体的数据类型,但

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

    看过阿里巴巴开发手册的同学应该都会对Integer临界值127有点印象. 原文中写的是: [强制]所有整型包装类对象之间值的比较,全部使用 equals 方法比较. 说明:对于 Integer var = ? 在-128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生, 会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都 会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法

  • Vue3中使用vant的踩坑实战日记

    目录 前言 一.下载vant 二.下载插件 三.配置插件 四.简单使用 五.我的解决方法 总结 前言 我照着视频中老师教的方式去使用vant(和官网教程一样),发现样式根本不起作用(想截个图来着,但是vite热更新太厉害了,找不到了哈哈哈),然后又反复看了视频一遍,检查自己插件啥的而又没有安装好,发现和老师的一样....,头疼…害...,幸好我最后在想用不用在main.js引入vant(因为老师说插件会自动识别,所以一开始一直以为是自己配置或者代码写错了的问题QAQ),最后成功了嘿嘿嘿(但是这样

  • JAVA中Integer值的范围实例代码

    废话不多说了,直接给大家贴代码,具体代码如下所示: package com.test; public class Test { public static void main(String []args) { Integer a = 100;//此处若使用new,则==值必为false Integer b = 100; System.out.println(a==b);//true Integer c = 150; Integer d = 150; System.out.println(c==d

  • Java中Integer.valueOf,parsetInt() String.valueOf的区别和结果代码解析

    先来看段代码 public class IntegerDemo { public static void main(String[] args) { String num = null; System.out.println( Integer.parseInt(num));// Exception java.lang.NumberFormatException System.out.println( Integer.valueOf(num));// Exception java.lang.Num

  • Java中Integer类型值相等判断方法

    背景 本周开发中遇到一个很低级的问题,Integer包装类的相等判断,包装类与基本数据类型的区别,应该大多数人在面试中经常被问到,但是有的时候大家都会烦这些看起来没啥用的东西,面试前还需要去熟悉,博主之前也是这样认为的,但是平时看一些理论性的东西,在方案探讨或者可行性分析时是很必要的,废话不多少,看看这个问题吧 事故现场 public static void main(String[] args) { Integer a =127; Integer b = 127; Integer c = 12

  • 你知道在Java中Integer和int的这些区别吗?

    一.基本概念(重要) Integer 是 int 的包装类,int 则是 java 的一种基本数据类型: Integer 变量必须实例化后才能使用,而int变量不需要: Integer 实际是对象的引用,当new一个 Integer时,实际上是生成一个指针指向此对象:而 int 则是直接存储数据值: Integer的默认值是null,int的默认值是0. 二.拓展 基于以上的一些概念,这里我们拓展一下,对于Integer包装类型与int基本数据类型之间数值相互比较的结果进行一下说明,这个也可能在

  • Java List的remove()方法踩坑

    目录 1.普通for循环遍历List删除指定元素--错误!!! 2.for循环遍历List删除元素时,让索引同步调整--正确! 3.倒序遍历List删除元素--正确! 4.foreach遍历List删除元素--错误!!! 5.迭代删除List元素--正确! 6.迭代遍历,用list.remove(i)方法删除元素--错误!!! 7.List删除元素时,注意Integer类型和int类型的区别. 总结: Java的List在删除元素时,一般会用list.remove(o)/remove(i)方法.

  • Java十道入门易踩坑题分析前篇

    目录 1,java基本类型 2,java包装类 3,Java编译 4,JDK,JVM,JRE 5,类型转换 6,转义字符 7,标识符 8,类型转换 9,赋值符号 10,打印一个字符串 1,java基本类型 下面属于java基本数据类型的有( ) A.String B.byte C.char D.Array Java基本数据类型分为三种,数值型,字符型,布尔型 数值型: 整型:byte.short.int.long 浮点型:double.float 字符型:char 布尔型:boolean Arr

  • Java十道入门易踩坑题分析后篇

    目录 一,写在前面 二,代码分析 代码分析① 代码分析② 代码分析③ 代码分析④ 代码分析⑤ 代码分析⑥ 代码分析⑦ 代码分析⑧ 代码分析⑨ 代码分析⑩ 一,写在前面 本篇主要讲类和对象这一章节的踩坑题,这一章也相对复杂和难理解,面试也是常考的一类题,我分析的都是比较经典的,读者觉得自己学习的不够扎实,可以收藏,如果觉得写发不错的话,求个免费的赞,谢谢! 二,代码分析 代码分析① 阅读如下代码. 请问,对语句行 test.hello(). 描述正确的有() package NowCoder; c

  • Swift踩坑实战之一个字符引发的Crash

    最近因为一个字符引发了 Crash,因为实际的业务场景不便描述,这里便用一段测试代码作说明. 话不多说,直接上代码: let testCharacters: Set<Character> = ["!", "\"", "$", "%", "&", "'", "+", ",", "<", &quo

随机推荐