細節決定成敗,開發中往往從一些細節就可以看出一個程序員的開發水準,下面我就給大家分享一下開發中最最常見的int轉換為String類型的方法及其性能解析。
一般大家最常用的方法有
方法一:String s1 = String.valueOf(i);?
方法二:String s2 = i+"";
不知道有沒有人用這種方法呢?
方法三:String s3 = Integer.toString(i);
繼續往下看之前,大家先猜測一下這三種方法哪種方法的效率最高,耗時最短,對內存消耗最小?相信結果會令你大吃一驚!
話不多說,直接上代碼,用事實說話。
package com.zhu.test;public class IntToStringOptimize {public static void main(String[] args) {//1.String.valueOf(i)方式long t = System.currentTimeMillis();for (int i = 0; i < 100000; i++) {String s0 = String.valueOf(i);}System.out.println("String.valueOf(i)方式耗時:" + (System.currentTimeMillis() - t));//2.i+""方式t = System.currentTimeMillis();for (int i = 0; i < 100000; i++) {String s = "" + i;}System.out.println("i+ \"\" 方式耗時 :" + (System.currentTimeMillis() - t));//3.Integer.toString(i)方式t = System.currentTimeMillis();for (int i = 0; i < 100000; i++) {String s = Integer.toString(i);}System.out.println("Integer.toString(i)方式耗時:" + (System.currentTimeMillis() - t));} }
?
運行結果如下:
結果是不是大跌眼鏡啊?沒想到我們最常用的i+""的性能竟然如此之差!而性能最好的竟然是沒人怎么用的toString(i);為什么會這樣呢?經過堆棧分析發現:
String.valueOf(i)的方法調用的竟然時第三種方法:Integer.toString(i),多此調試后發現他們的耗時比基本保持在20:8,那么toString(i)的內部又是怎樣實現的呢?
下面是Integer.toString(i)的實現代碼:
1 public static String toString(int i) { 2 if (i == Integer.MIN_VALUE) 3 return "-2147483648"; 4 int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); 5 char[] buf = new char[size]; 6 getChars(i, size, buf); 7 return new String(buf, true); 8 }
其中stringSize(i)又做了什么事呢?經過進一步跟蹤發現
1 static int stringSize(int x) { 2 for (int i=0; ; i++) 3 if (x <= sizeTable[i]) 4 return i+1; 5 }
而sizeTable[]又是一個怎樣的數組呢?繼續往下看,
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,99999999, 999999999, Integer.MAX_VALUE };
原來在調用toString(i)的時候,如果會判斷i是否是負數,如果是負數就將其求反為正數,然后會根據 sizeTable數組來 判斷 i 的位數并返回創建一個比i的長度+1的字符數組,比如i=11,那么size就是3,然后就會創建一個3位的字符數組。那么問題來了,getChars()有是干什么的呢?
1 /** 2 * Places characters representing the integer i into the 3 * character array buf. The characters are placed into 4 * the buffer backwards starting with the least significant 5 * digit at the specified index (exclusive), and working 6 * backwards from there. 7 * 8 * Will fail if i == Integer.MIN_VALUE 9 */ 10 static void getChars(int i, int index, char[] buf) { 11 int q, r; 12 int charPos = index; 13 char sign = 0; 14 15 if (i < 0) { 16 sign = '-'; 17 i = -i; 18 } 19 20 // Generate two digits per iteration 21 while (i >= 65536) { 22 q = i / 100; 23 24 r = i - ((q << 6) + (q << 5) + (q << 2)); 25 i = q; 26 buf [--charPos] = DigitOnes[r]; 27 buf [--charPos] = DigitTens[r]; 28 } 29 30 // Fall thru to fast mode for smaller numbers 31 // assert(i <= 65536, i); 32 for (;;) { 33 q = (i * 52429) >>> (16+3); 34 r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... 35 buf [--charPos] = digits [r]; 36 i = q; 37 if (i == 0) break; 38 } 39 if (sign != 0) { 40 buf [--charPos] = sign; 41 } 42 }
仔細分析代碼發現,這個函數的功能就是將int型的i從右向左(即從個位數開始)填充到字符數組buf中。至此方法一String.valueOf(i)和方法三Integer.toString(i)分析完畢。
由上可見,方式二 i+"" 是最耗時耗內存的方法,之所以寫這篇文章是因為我在看一段視頻的時候以為老師說他以前剛入職的時候就是用這種方法從而項目中出現大量的+"",結果是被項目經理批評了一頓。所以小伙伴們,如果你還在用方法二就趕快更正過來吧!
那么方法二為什么會這么耗時呢?
因為每 +"" 一次,就會調用一次?
public StringBuffer() {
super(16);
}
方法,這就意味著每 +"" 一次,就會在內存中實例化一個StringBuffer()對象,原因是String類型是final的,其內容是不可變的,所以每次改變其值就要重新new一個對象,如果一個項目中大量使用該方法,不耗時耗內存才怪呢。
個人總結:看到這里相信大家都知道了到底哪種方法才是最有效的,int類型轉為String類型時使用Integer.toString(i)或String.valueOf(i)方法會比+""高效節能的多。希望閱讀此文能提升一下讀者的逼格,如果有哪個地方我分析的不對或者有什么更好的建議或更實用的細節還請小伙伴們不吝賜教!
?