一場由Java中Integer引發(fā)的踩坑實(shí)戰(zhàn)
看過阿里巴巴開發(fā)手冊的同學(xué)應(yīng)該都會對Integer臨界值127有點(diǎn)印象。
原文中寫的是:
【強(qiáng)制】所有整型包裝類對象之間值的比較,全部使用 equals 方法比較。
說明:對于 Integer var = ? 在-128 至 127 之間的賦值,Integer 對象是在 IntegerCache.cache 產(chǎn)生,
會復(fù)用已有對象,這個(gè)區(qū)間內(nèi)的 Integer 值可以直接使用==進(jìn)行判斷,但是這個(gè)區(qū)間之外的所有數(shù)據(jù),都
會在堆上產(chǎn)生,并不會復(fù)用已有對象,這是一個(gè)大坑,推薦使用 equals 方法進(jìn)行判斷。
沒錯(cuò),文中要求Integer對象比較的時(shí)候必須要用equals進(jìn)行。
然后很多同學(xué)對于為什么要這么干沒什么感覺。對于IntegerCache.cache也沒什么感覺。
很多時(shí)候我們寫的代碼可能是這樣的:
Integer num = 127; if(num==128){ //... }
這種情況下,我們拿Integer和一個(gè)數(shù)字比較的時(shí)候,是不會出什么問題。
然后如果我們這樣寫
Integer num1 = 127; num1++; Integer num2= 128; if (num1 == num2) { System.out.println(true); } else{ System.out.println(false); }
神奇的事情發(fā)生了,num1和num2雖然都是128,但是他們并不相等。
這是因?yàn)镮nteger的值如果是-128~127之間的時(shí)候,Integer并不會創(chuàng)建新的對象,而是從IntegerCache.cache中取出的,所以他們隨便比較都沒有問題。
但是如果超出了這個(gè)范圍,就不一樣了。
不信你可以試試下面的代碼:
Integer num1 = 127; Integer num2= 127; if (num1 == num2) { System.out.println(true); } else{ System.out.println(false); }
=================================
可惜的是工作中常常忘記了這一點(diǎn),于是一場意外發(fā)生了。
本人前段時(shí)間寫的一段代碼中有下面一段:
String standardItemNameStr = sampleStandardItemList.stream() .filter(item -> item.getSampleId()==sample.getSampleId()) .map(item -> item.getStandardItemName()).collect(Collectors.joining("、"));
系統(tǒng)剛剛上線的時(shí)候一切NICE,運(yùn)行很正常。突然有一天出事了??蛻舾答伋鯞UG了。
本該顯示數(shù)據(jù)的地方,成了空值。
自己在本地測試,一切OK。代碼檢測了十遍以上,沒發(fā)現(xiàn)什么問題。
把生產(chǎn)環(huán)境的數(shù)據(jù)DOWN下來一跑發(fā)現(xiàn)其中第二行item.getSampleId()
的值是180,這時(shí)突然想起Integer的這個(gè)設(shè)定。二話不說,修改為下面的代碼,一切恢復(fù)正常。
String standardItemNameStr = sampleStandardItemList.stream() .filter(item -> item.getSampleId() .equals(sample.getSampleId())) .map(item -> item.getStandardItemName()).collect(Collectors.joining("、"));
這個(gè)問題雖然很簡單,但還是很容易忽略的。由此也擴(kuò)展思考了一下,去測試一下Double、Float包裝類,并沒有catch這類的設(shè)計(jì)思路。
原因嘛應(yīng)該也很簡單,Integer是整數(shù),很多時(shí)候我們用Integer的時(shí)候需要用到的值確實(shí)是比較小的,所以官方做個(gè)catch確實(shí)能起到提高執(zhí)行效率的作用,而且這個(gè)緩存命中率還是比較高的,但是小數(shù)的主要用途是在小數(shù)方面,如果要做catch的話,那數(shù)量可就太多了。
那么byte、short、long的包裝類會不會也有catch的設(shè)計(jì)呢?
補(bǔ)充:Java Integer比較中的那些坑
前幾天同事偶然遇到的一個(gè)問題,在list中查詢出重復(fù)的值,留下第一個(gè),其余刪除。
ArrayList<Integer> a//a中裝有要操作的數(shù)據(jù),都是數(shù)字 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); } } }
然后喜聞樂見的程序出問題了:程序無法將相同的值除第一個(gè)外刪除掉。說起來這也是一個(gè)比較基礎(chǔ)性的問題。
int為基本類型,Integer類型為基本包裝類型。因而可以將Integer當(dāng)做一個(gè)對象來理解,所以在上面的代碼示例中,用==來比較2個(gè)對象的引用無疑就是在搞笑了,地址都不一樣,怎么可能返回true。
但是這里存在著一些坑,就是Integer有時(shí)候用==比較是可以得到true的(值相同),原因如下:
在-128至127之間的賦值,Integer對象是在IntegerCache.cache產(chǎn)生,會復(fù)用已有對象,這個(gè)區(qū)間內(nèi)的Integer值可以直接使用==進(jìn)行判斷,但是這個(gè)區(qū)間之外的所有數(shù)據(jù),都會在堆上產(chǎn)生,并不會復(fù)用已有對象。
所以推薦都使用equals比較。
附上int類型自動裝箱為Integer時(shí)的源代碼(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); }
這里還牽涉到了一點(diǎn),就是這里為什么不直接用int類型呢?這是因?yàn)锳rrayList中只接受Object對象,實(shí)際情況如下:
ArrayList al=new ArrayList(); int n=40; Integer nI=new Integer(n); al.add(n);//不可以 al.add(nI);//可以
總結(jié)
到此這篇關(guān)于一場由Java中Integer引發(fā)的踩坑實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Java中Integer踩坑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡介Java的Spring框架的體系結(jié)構(gòu)以及安裝配置
這篇文章主要介紹了Java的Spring框架的體系結(jié)構(gòu)以及安裝配置,Spring框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12基于Retrofit+Rxjava實(shí)現(xiàn)帶進(jìn)度顯示的下載文件
這篇文章主要為大家詳細(xì)介紹了基于Retrofit+Rxjava實(shí)現(xiàn)帶進(jìn)度顯示的下載文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05導(dǎo)出maven項(xiàng)目依賴的jar包(圖文教程)
下面小編就為大家?guī)硪黄獙?dǎo)出maven項(xiàng)目依賴的jar包(圖文教程)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10Java純代碼實(shí)現(xiàn)導(dǎo)出PDF功能
在項(xiàng)目開發(fā)中,產(chǎn)品的需求越來越奇葩啦,開始文件下載都是下載為excel的,做著做著需求竟然變了,要求能導(dǎo)出pdf,本文就來和大家分享一下Java實(shí)現(xiàn)導(dǎo)出PDF的常用方法吧2023-07-07