日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

java 代码性能优化_Java代码性能优化(四)

發(fā)布時(shí)間:2025/10/17 java 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 代码性能优化_Java代码性能优化(四) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.奇偶判斷

不要使用 i % 2 == 1 來(lái)判斷是否是奇數(shù),因?yàn)閕為負(fù)奇數(shù)時(shí)不成立,請(qǐng)使用 i % 2 != 0 來(lái)判斷是否是奇數(shù),或使用高效式 (i & 1) != 0來(lái)判斷。

2.小數(shù)精確計(jì)算System.out.println(2.00?-1.10);//?0.8999999999999999

上面的計(jì)算出的結(jié)果不是 0.9,而是一連串的小數(shù)。問(wèn)題在于1.1這個(gè)數(shù)字不能被精確表示為一個(gè)double,因此它被表示為最接近它的double值,該程序從2中減去的就是這個(gè)值,但這個(gè)計(jì)算的結(jié)果并不是最接近0.9的double值。

一般地說(shuō),問(wèn)題在于并不是所有的小數(shù)都可以用二進(jìn)制浮點(diǎn)數(shù)精確表示。二進(jìn)制浮點(diǎn)對(duì)于貨幣計(jì)算是非常不適合的,因?yàn)樗豢赡軐?.0表示成10的其他任何負(fù)次冪。解決問(wèn)題的第一種方式是使用貨幣的最小單位(分)來(lái)表示:System.out.println(200-110);?//?90

第二種方式是使用BigDecimal,但一定要用BigDecimal(String)構(gòu)造器,而千萬(wàn)不要用 BigDecimal(double)來(lái)構(gòu)造(也不能將float或double型轉(zhuǎn)換成String再來(lái)使用BigDecimal(String)來(lái)構(gòu)造,因?yàn)樵趯loat或double轉(zhuǎn)換成String時(shí)精度已丟失)。

例如new BigDecimal(0.1),它將返回一個(gè)BigDecimal,也即0.1000000000000000055511151231257827021181583404541015625,正確使用BigDecimal,程序就可以打印出我們所期望的結(jié)果0.9:System.out.println(new?BigDecimal("2.0").subtract(new?BigDecimal("1.10")));//?0.9

另外,如果要比較兩個(gè)浮點(diǎn)數(shù)的大小,要使用BigDecimal的compareTo方法。

3.int整數(shù)相乘溢出

我們計(jì)算一天中的微秒數(shù):long?microsPerDay?=?24?*?60?*?60?*?1000?*?1000;//?正確結(jié)果應(yīng)為:86400000000

System.out.println(microsPerDay);//?實(shí)際上為:500654080

問(wèn)題在于計(jì)算過(guò)程中溢出了。這個(gè)計(jì)算式完全是以int運(yùn)算來(lái)執(zhí)行的,并且只有在運(yùn)算完成之后,其結(jié)果才被提升為long,而此時(shí)已經(jīng)太遲:計(jì)算已經(jīng)溢出。

解決方法使計(jì)算表達(dá)式的第一個(gè)因子明確為long型,這樣可以強(qiáng)制表達(dá)式中所有的后續(xù)計(jì)算都用long運(yùn)算來(lái)完成,這樣結(jié)果就不會(huì)溢出:long?microsPerDay?=?24L?*?60?*?60?*?1000?*?1000;

4.負(fù)的十六進(jìn)制與八進(jìn)制字面常量

“數(shù)字字面常量”的類型都是int型,而不管他們是幾進(jìn)制,所以“2147483648”、“0x180000000(十六進(jìn)制,共33位,所以超過(guò)了整數(shù)的取值范圍)”字面常量是錯(cuò)誤的,編譯時(shí)會(huì)報(bào)超過(guò)int的取值范圍了,所以要確定以long來(lái)表示“2147483648L”“0x180000000L”。

十進(jìn)制字面常量只有一個(gè)特性,即所有的十進(jìn)制字面常量都是正數(shù),如果想寫一個(gè)負(fù)的十進(jìn)制,則需要在正的十進(jìn)制字面常量前加上“-”即可。

十六進(jìn)制或八進(jìn)制字面常量可就不一定是正數(shù)或負(fù)數(shù),是正還是負(fù),則要根據(jù)當(dāng)前情況看:如果十六進(jìn)制和八進(jìn)制字

面常量的最高位被設(shè)置成了1,那么它們就是負(fù)數(shù):System.out.println(0x80);//128

//0x81看作是int型,最高位(第32位)為0,所以是正數(shù)

System.out.println(0x81);//129

System.out.println(0x8001);//32769

System.out.println(0x70000001);//1879048193

//字面量0x80000001為int型,最高位(第32位)為1,所以是負(fù)數(shù)

System.out.println(0x80000001);//-2147483647

//字面量0x80000001L強(qiáng)制轉(zhuǎn)為long型,最高位(第64位)為0,所以是正數(shù)

System.out.println(0x80000001L);//2147483649

//最小int型

System.out.println(0x80000000);//-2147483648

//只要超過(guò)32位,就需要在字面常量后加L強(qiáng)轉(zhuǎn)long,否則編譯時(shí)出錯(cuò)

System.out.println(0x8000000000000000L);//-9223372036854775808

從上面可以看出,十六進(jìn)制的字面常量表示的是int型,如果超過(guò)32位,則需要在后面加“L”,否則編譯過(guò)不過(guò)。如果為32,則為負(fù)int正數(shù),超過(guò)32位,則為long型,但需明確指定為long。System.out.println(Long.toHexString(0x100000000L?+?0xcafebabe));//?cafebabe

結(jié)果為什么不是0x1cafebabe?該程序執(zhí)行的加法是一個(gè)混合類型的計(jì)算:左操作數(shù)是long型,而右操作數(shù)是int類型。為了執(zhí)行該計(jì)算,Java將int類型的數(shù)值用拓寬原生類型轉(zhuǎn)換提升為long類型,然后對(duì)兩個(gè)long類型數(shù)值相加。因?yàn)閕nt是有符號(hào)的整數(shù)類型,所以這個(gè)轉(zhuǎn)換執(zhí)行的是符號(hào)擴(kuò)展。

這個(gè)加法的右操作數(shù)0xcafebabe為32位,將被提升為long類型的數(shù)值0xffffffffcafebabeL,之后這個(gè)數(shù)值加上了左操作0x100000000L。當(dāng)視為int類型時(shí),經(jīng)過(guò)符號(hào)擴(kuò)展之后的右操作數(shù)的高32位是-1,而左操作數(shù)的第32位是1,兩個(gè)數(shù)值相加得到了0:

0x 0xffffffffcafebabeL

+ 0x 0000000100000000L

-----------------------------

0x 00000000cafebabeL

如果要得到正確的結(jié)果0x1cafebabe,則需在第二個(gè)操作數(shù)組后加上“L”明確看作是正的long型即可,此時(shí)相加時(shí)拓展符號(hào)位就為0:System.out.println(Long.toHexString(0x100000000L?+?0xcafebabeL));//?1cafebabe

5.窄數(shù)字類型提升至寬類型時(shí)使用符號(hào)位擴(kuò)展還是零擴(kuò)展System.out.println((int)(char)(byte)-1);//?65535

結(jié)果為什么是65535而不是-1?

窄的整型轉(zhuǎn)換成較寬的整型時(shí)符號(hào)擴(kuò)展規(guī)則:如果最初的數(shù)值類型是有符號(hào)的,那么就執(zhí)行符號(hào)擴(kuò)展(即如果符號(hào)位為1,則擴(kuò)展為1,如果為零,則擴(kuò)展為0);如果它是char,那么不管它將要被提升成什么類型,都執(zhí)行零擴(kuò)展。了解上面的規(guī)則后,我們?cè)賮?lái)看看迷題:因?yàn)閎yte是有符號(hào)的類型,所以在將byte數(shù)值-1(二進(jìn)制為:11111111)提升到char時(shí),會(huì)發(fā)生符號(hào)位擴(kuò)展,又符號(hào)位為1,所以就補(bǔ)8個(gè)1,最后為16個(gè)1;然后從char到int的提升時(shí),由于是char型提升到其他類型,所以采用零擴(kuò)展而不是符號(hào)擴(kuò)展,結(jié)果int數(shù)值就成了65535。如果將一個(gè)char數(shù)值c轉(zhuǎn)型為一個(gè)寬度更寬的類型時(shí),只是以零來(lái)擴(kuò)展,但如果清晰表達(dá)以零擴(kuò)展的意圖,則可以考慮

使用一個(gè)位掩碼:int?i?=?c?&?0xffff;//實(shí)質(zhì)上等同于:int?i?=?c?;

如果將一個(gè)char數(shù)值c轉(zhuǎn)型為一個(gè)寬度更寬的整型,并且希望有符號(hào)擴(kuò)展,那么就先將char轉(zhuǎn)型為一個(gè)short,它與char上個(gè)具有同樣的寬度,但是它是有符號(hào)的:int?i?=?(short)c;

如果將一個(gè)byte數(shù)值b轉(zhuǎn)型為一個(gè)char,并且不希望有符號(hào)擴(kuò)展,那么必須使用一個(gè)位掩碼來(lái)限制它:char?c?=?(char)(b?&?0xff);//?char?c?=?(char)?b;為有符號(hào)擴(kuò)展

6. ((byte)0x90 == 0x90)?

答案是不等的,盡管外表看起來(lái)是成立的,但是它卻等于false。為了比較byte數(shù)值(byte)0x90和int數(shù)值0x90,Java通過(guò)拓寬原生類型將byte提升為int,然后比較這兩個(gè)int數(shù)值。因?yàn)閎yte是一個(gè)有符號(hào)類型,所以這個(gè)轉(zhuǎn)換執(zhí)行的是符號(hào)擴(kuò)展,將負(fù)的byte數(shù)值提升為了在數(shù)字上相等的int值(10010000?111111111111111111111111 10010000)。在本例中,該轉(zhuǎn)換將(byte)0x90提升為int數(shù)值-112,它不等于int數(shù)值的0x90,即+144。

解決辦法:使用一個(gè)屏蔽碼來(lái)消除符號(hào)擴(kuò)展的影響,從而將byte轉(zhuǎn)型為int。((byte)0x90?&?0xff)==?0x90

7. 三元表達(dá)式(?:)char?x?=?'X';

int?i?=?0;

System.out.println(true???x?:?0);//?X

System.out.println(false???i?:?x);//?88

條件表達(dá)式結(jié)果類型的規(guī)則:

(1) 如果第二個(gè)和第三個(gè)操作數(shù)具有相同的類型,那么它就是條件表達(dá)式的類型。

(2) 如果一個(gè)操作的類型是T,T表示byte、short或char,而另一個(gè)操作數(shù)是一個(gè)int類型的“字面常量”,并且它的值可以用類型T表示,那條件表達(dá)式的類型就是T。

(3) 否則,將對(duì)操作數(shù)類型進(jìn)行提升,而條件表達(dá)式的類型就是第二個(gè)和第三個(gè)操作被提升之后的類型。

現(xiàn)來(lái)使用以上規(guī)則解上面的迷題,第一個(gè)表達(dá)式符合第二條規(guī)則:一個(gè)操作數(shù)的類型是char,另一個(gè)的類型是字面常量為0的int型,但0可以表示成char,所以最終返回類型以char類型為準(zhǔn);第二個(gè)表達(dá)式符合第三條規(guī)則:因?yàn)閕為int型變量,而x又為char型變量,所以會(huì)先將x提升至int型,所以最后的結(jié)果類型為int型,但如果將i定義成final時(shí),則返回結(jié)果類型為char,則此時(shí)符合第二條規(guī)則,因?yàn)閒inal類型的變量在編譯時(shí)就使用“字面常量0”來(lái)替換三元表達(dá)式了:final?int?i?=?0;

System.out.println(false???i?:?x);//?X

在JDK1.4版本或之前,條件操作符 ?: 中,當(dāng)?shù)诙€(gè)和延續(xù)三個(gè)操作數(shù)是引用類型時(shí),條件操作符要求它們其中一個(gè)必須是另一個(gè)的子類型,那怕它們有同一個(gè)父類也不行:public?class?T?{

public?static?void?main(String[]?args)?{

System.out.println(f());

}

public?static?T?f()?{

//?!!1.4不能編譯,但1.5可以

//?!!return?true?new?T1():new?T2();

return?true???(T)?new?T1()?:?new?T2();//?T1

}

}

class?T1?extends?T?{

public?String?toString()?{

return?"T1";

}

}

class?T2?extends?T?{

public?String?toString()?{

return?"T2";

}

}

在5.0或以上版本中,條件操作符在延續(xù)二個(gè)和第三個(gè)操作數(shù)是引用類型時(shí)總是合法的。其結(jié)果類型是這兩種類型的最小公共超類。公共超類總是存在的,因?yàn)镺bject是每一個(gè)對(duì)象類型的超類型,上面的最小公共超類是T,所以能編譯。在JAVA程序中,性能問(wèn)題的大部分原因并不在于JAVA語(yǔ)言,而是程序本身。養(yǎng)成良好的編碼習(xí)慣非常重要,能夠顯著地提升程序性能。

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的java 代码性能优化_Java代码性能优化(四)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。