【實(shí)例描述】
字符串是程序開發(fā)中使用最頻繁的數(shù)據(jù),在Java 中字符串是String 類的對(duì)象,它是不可變數(shù)據(jù),當(dāng)執(zhí)行字符串連接操作時(shí)將生成新的字符串,而不是修改原有的字符串,所以大量的字符串操作非常耗時(shí)。本實(shí)例將分別演示使用String 類與StringBuilder 類進(jìn)行3 萬個(gè)字符串追加的操作,并輸出其運(yùn)行時(shí)間。我們可以對(duì)比兩次方法執(zhí)行的時(shí)間。運(yùn)行效果如圖4.26 所示。
【實(shí)現(xiàn)過程】
在Eclipse 中新建項(xiàng)目BuilderString,并在其中創(chuàng)建一個(gè)BuilderString.java 文件。在該類的主方法中創(chuàng)建字符串對(duì)象appendStr,并通過循環(huán)為該字符串連接3 萬個(gè)字符,計(jì)算并輸出其用時(shí)。再創(chuàng)建StringBuilder 字符串構(gòu)造器,同樣為其追加3 萬個(gè)字符,計(jì)算并輸出其用時(shí)。核心代碼如下所示:
public class BuilderString {
public static void main(String[] args) {
String appendStr = ""; // 創(chuàng)建字符串變量
long startTime = System.nanoTime(); // 開始記事
for (int i = 20000; i < 50000; i++) { // 遍歷30000 個(gè)字符
appendStr += (char) i; // 字符串與每個(gè)字符執(zhí)行連接操作
}
long endTime = System.nanoTime(); // 結(jié)束計(jì)時(shí)
System.out.println("String 追加字符3 萬個(gè)。");
// 輸出用時(shí)
System.out.println("用時(shí):" + (endTime - startTime) / 1000000d + "毫秒
");
StringBuilder strBuilder = new StringBuilder(); // 創(chuàng)建字符串構(gòu)建器
startTime = System.nanoTime(); // 開始計(jì)時(shí)
for (int i = 20000; i < 50000; i++) { // 遍歷30000 個(gè)字符
strBuilder.append((char) i); // 把每個(gè)字符追加到構(gòu)建器
}
endTime = System.nanoTime(); // 結(jié)束計(jì)時(shí)
System.out.println("StringBuilder 字符串構(gòu)建器追加字符3 萬個(gè)。");
// 輸出用時(shí)
System.out.print("用時(shí):" + (endTime - startTime) / 1000000d + "毫秒");
}
}
【代碼解析】
從JDK 5.0 開始,Java 增添了一個(gè)單個(gè)線程使用的等價(jià)類,即StringBuilder。通常應(yīng)該優(yōu)先使用StringBuilder 類,因?yàn)樗С炙邢嗤牟僮鳎捎谒粓?zhí)行同步,所以速度更快。但是,如果將StringBuilder 的實(shí)例用于多個(gè)線程是不安全的,這時(shí)我們則建議使用StringBuffer。
【知識(shí)擴(kuò)展】
在性能強(qiáng)弱上:StringBuilder>StringBuffer>String。有關(guān)這三者的性能問題我們?cè)偬崾疽韵聨c(diǎn):
1. 為了獲得更好的性能,在構(gòu)造StringBuffer 或StringBuilder 時(shí)應(yīng)盡可能指定它的容量。當(dāng)然,如果你操作的字符串長度不超過16 個(gè)字符就不用了。
2. 相同情況下使用StringBuilder 與使用StringBuffer 相比,僅能獲得10%~15%左右的性能提升,但卻要冒多線程不安全的風(fēng)險(xiǎn)。而在現(xiàn)實(shí)的模塊化編程中,負(fù)責(zé)某一模塊的程序員不一定能清晰地判斷該模塊是否會(huì)放入多線程的環(huán)境中運(yùn)行,因此,除非能確定你的系統(tǒng)瓶頸是在StringBuffer 上,并且確定你的模塊不會(huì)運(yùn)行在多線程模式下,否則還是用StringBuffer。
3. 用好現(xiàn)有的類比引入新的類更重要。很多程序員在使用StringBuffer 時(shí)是不指定其容量的,如果這樣的習(xí)慣帶StringBuilder 的使用中,只能獲得10%左右的性能提升;但如果使用指定容量的StringBuffer,將馬上獲得45%左右的性能提升,甚至比不使用指定容量的StringBuilder 快30%左右。