java 開發(fā)使用字符串和數(shù)字的性能分析
java 開發(fā)使用字符串和數(shù)字的性能分析
前言:
分析使用字符串和數(shù)字,在軟件產(chǎn)品上線后用戶較多的情況下,很有必要考慮的問(wèn)題,這直接體現(xiàn)了用戶的體驗(yàn)程度,總不能讓用戶用著很卡的感覺吧!
在我多年的開發(fā)經(jīng)驗(yàn)中,經(jīng)常發(fā)現(xiàn)的一個(gè)情況就是,很多項(xiàng)目的對(duì)象字段或者是數(shù)據(jù)庫(kù)字段本來(lái)是數(shù)字類型的,卻被定義成字符串類型,這無(wú)關(guān)痛癢嗎?
對(duì)于小項(xiàng)目來(lái)說(shuō),可能沒什么影響,反正只要業(yè)務(wù)邏輯正確即可,性能沒什么問(wèn)題,因?yàn)閿?shù)據(jù)也不多,用戶也不多。
然而,對(duì)于大數(shù)據(jù)處理來(lái)說(shuō),這個(gè)可不是小事,從字符串替換為數(shù)字類型,可以極大地節(jié)省內(nèi)存、磁盤存儲(chǔ)以及網(wǎng)絡(luò)帶寬,減少IO的代價(jià),而且很多數(shù)據(jù)結(jié)構(gòu)和算法使用數(shù)字類型比字符串要更快。
我們來(lái)看一個(gè)例子,假設(shè)你有很多的日志需要處理,而每條日志都有一個(gè)唯一的標(biāo)識(shí),標(biāo)識(shí)類似這樣的格式:
F5051582611729507844 3832154813577306424 F1624235934976711017 3810376634214027595 F6884923813121317381 7278044081826528150
看到這些標(biāo)識(shí),你怎么想?我的第一反應(yīng)應(yīng)該是數(shù)字,可是怎么有個(gè)F呢?我想可以把它當(dāng)做16進(jìn)制。后來(lái)發(fā)現(xiàn)可以把F當(dāng)做負(fù)號(hào),這就是一個(gè)64位的長(zhǎng)整型。
那么如果你把這些標(biāo)識(shí)當(dāng)成字符串,會(huì)有什么不同呢?
當(dāng)然有,如果你每秒要處理這樣的日志百萬(wàn)或者千萬(wàn)條,每條處理結(jié)果可能會(huì)包含百萬(wàn)或者千萬(wàn)個(gè)這樣的標(biāo)識(shí)元素構(gòu)成的集合,這個(gè)不同就會(huì)體現(xiàn)的非常明顯。
下面,我們來(lái)分析一下標(biāo)識(shí)3832154813577306424的存儲(chǔ)占用情況:
1、內(nèi)存占用
當(dāng)做字符串:我們知道,JAVA中字符串是由字符構(gòu)成的,一個(gè)字符是由2個(gè)字節(jié)構(gòu)成的(這是JAVA的悲劇了),上述標(biāo)識(shí)有19個(gè)字符,所以,占用的內(nèi)存大小為:19*2+4=42(字節(jié)),+4是因?yàn)樽址褂靡粋€(gè)整型保存字符串的哈希值。
當(dāng)做數(shù)字:如當(dāng)做長(zhǎng)整型,則占用的內(nèi)存大小為8字節(jié)。
這里有5倍以上的差距了吧。
2、序列化字節(jié)大小
當(dāng)我們需要通過(guò)網(wǎng)絡(luò)傳輸這些標(biāo)識(shí)或者需要把這些標(biāo)識(shí)存儲(chǔ)到磁盤中的時(shí)候,我們就需要把這些標(biāo)識(shí)轉(zhuǎn)換為字節(jié)數(shù)組,如何轉(zhuǎn)換為字節(jié)數(shù)組呢?我們可以使用多種編碼方式。
當(dāng)做字符串:我們知道,JAVA中字符串轉(zhuǎn)換為字節(jié)數(shù)組可以使用多種編碼方式,我們看看常見的編碼方式對(duì)如上字符串編碼之后的字節(jié)數(shù):
String abc = "3832154813577306424"; System.out.println("3832154813577306424 length:"+abc.length()); System.out.println(Charset.defaultCharset().name()+":"+abc.getBytes().length); System.out.println("unicode:"+abc.getBytes("unicode").length); System.out.println("gbk:"+abc.getBytes("gbk").length); System.out.println("gb2312:"+abc.getBytes("gb2312").length); System.out.println("ISO-8859-1:"+abc.getBytes("ISO-8859-1").length);
輸出如下:
3832154813577306424 length:19 UTF-8:19 unicode:40 gbk:19 gb2312:19 ISO-8859-1:19
當(dāng)做數(shù)字:如當(dāng)做長(zhǎng)整型,則占用的內(nèi)存大小為8字節(jié)。
這里有2倍以上的差距了吧。
那么我們?nèi)绾卧陂L(zhǎng)整型和字節(jié)數(shù)組之間轉(zhuǎn)換呢?
String abc = "3832154813577306424"; System.out.println("3832154813577306424 length:"+abc.length()); System.out.println("long:"+ByteUtils.longToBytes(Long.parseLong(abc)).length); byte[] bytes = ByteUtils.longToBytes(Long.parseLong(abc)); System.out.println("string:"+ByteUtils.bytesToLong(bytes));
輸出如下:
3832154813577306424 length:19 long:8 string:3832154813577306424
public static byte[] longToBytes(long x) { ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES); longBuffer.putLong(0, x); return longBuffer.array(); } public static long bytesToLong(byte[] bytes) { return bytesToLong(bytes, 0, bytes.length); } public static long bytesToLong(byte[] bytes, int offset, int length) { ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES); longBuffer.put(bytes, offset, length); longBuffer.flip();//need flip return longBuffer.getLong(); }
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
兩天沒解決的問(wèn)題chatgpt用了5秒搞定隱藏bug
這篇文章主要為大家描述了我用了兩天沒解決的問(wèn)題chatgpt用了5秒搞定的全程介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04Spring中@RabbitHandler和@RabbitListener的區(qū)別詳析
@RabbitHandler是用于處理消息的方法注解,它與@RabbitListener注解一起使用,這篇文章主要給大家介紹了關(guān)于Spring中@RabbitHandler和@RabbitListener區(qū)別的相關(guān)資料,需要的朋友可以參考下2024-02-02

java8 stream的多字段排序?qū)崿F(xiàn)(踩坑)

Springboot項(xiàng)目?jī)?yōu)雅地處理日志的方法詳解

無(wú)感NullPointerException的值相等判斷方法

Spring mvc整合mybatis(crud+分頁(yè)插件)操作mysql