前言:
分析使用字符串和數(shù)字,在軟件產(chǎn)品上線后用戶較多的情況下,很有必要考慮的問題,這直接體現(xiàn)了用戶的體驗程度,總不能讓用戶用著很卡的感覺吧!
在我多年的開發(fā)經(jīng)驗中,經(jīng)常發(fā)現(xiàn)的一個情況就是,很多項目的對象字段或者是數(shù)據(jù)庫字段本來是數(shù)字類型的,卻被定義成字符串類型,這無關(guān)痛癢嗎?
對于小項目來說,可能沒什么影響,反正只要業(yè)務(wù)邏輯正確即可,性能沒什么問題,因為數(shù)據(jù)也不多,用戶也不多。
然而,對于大數(shù)據(jù)處理來說,這個可不是小事,從字符串替換為數(shù)字類型,可以極大地節(jié)省內(nèi)存、磁盤存儲以及網(wǎng)絡(luò)帶寬,減少IO的代價,而且很多數(shù)據(jù)結(jié)構(gòu)和算法使用數(shù)字類型比字符串要更快。
我們來看一個例子,假設(shè)你有很多的日志需要處理,而每條日志都有一個唯一的標(biāo)識,標(biāo)識類似這樣的格式:
1
2
3
4
5
6
|
F5051582611729507844 3832154813577306424 F1624235934976711017 3810376634214027595 F6884923813121317381 7278044081826528150 |
看到這些標(biāo)識,你怎么想?我的第一反應(yīng)應(yīng)該是數(shù)字,可是怎么有個F呢?我想可以把它當(dāng)做16進(jìn)制。后來發(fā)現(xiàn)可以把F當(dāng)做負(fù)號,這就是一個64位的長整型。
那么如果你把這些標(biāo)識當(dāng)成字符串,會有什么不同呢?
當(dāng)然有,如果你每秒要處理這樣的日志百萬或者千萬條,每條處理結(jié)果可能會包含百萬或者千萬個這樣的標(biāo)識元素構(gòu)成的集合,這個不同就會體現(xiàn)的非常明顯。
下面,我們來分析一下標(biāo)識3832154813577306424的存儲占用情況:
1、內(nèi)存占用
當(dāng)做字符串:我們知道,JAVA中字符串是由字符構(gòu)成的,一個字符是由2個字節(jié)構(gòu)成的(這是JAVA的悲劇了),上述標(biāo)識有19個字符,所以,占用的內(nèi)存大小為:19*2+4=42(字節(jié)),+4是因為字符串使用一個整型保存字符串的哈希值。
當(dāng)做數(shù)字:如當(dāng)做長整型,則占用的內(nèi)存大小為8字節(jié)。
這里有5倍以上的差距了吧。
2、序列化字節(jié)大小
當(dāng)我們需要通過網(wǎng)絡(luò)傳輸這些標(biāo)識或者需要把這些標(biāo)識存儲到磁盤中的時候,我們就需要把這些標(biāo)識轉(zhuǎn)換為字節(jié)數(shù)組,如何轉(zhuǎn)換為字節(jié)數(shù)組呢?我們可以使用多種編碼方式。
當(dāng)做字符串:我們知道,JAVA中字符串轉(zhuǎn)換為字節(jié)數(shù)組可以使用多種編碼方式,我們看看常見的編碼方式對如上字符串編碼之后的字節(jié)數(shù):
1
2
3
4
5
6
7
8
|
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); |
輸出如下:
1
2
3
4
5
6
|
3832154813577306424 length: 19 UTF- 8 : 19 unicode: 40 gbk: 19 gb2312: 19 ISO- 8859 - 1 : 19 |
當(dāng)做數(shù)字:如當(dāng)做長整型,則占用的內(nèi)存大小為8字節(jié)。
這里有2倍以上的差距了吧。
那么我們?nèi)绾卧陂L整型和字節(jié)數(shù)組之間轉(zhuǎn)換呢?
1
2
3
4
5
6
|
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)); |
輸出如下:
1
2
3
|
3832154813577306424 length: 19 long : 8 string: 3832154813577306424 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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(); } |
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!