讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議54:正確使用String、StringBuffer、StringBuilder >

建議54:正確使用String、StringBuffer、StringBuilder

CharSequence接口有三個實現類與字符串有關:String、StringBuffer、StringBuilder,雖然它們都與字符串有關,但是其處理機制是不同的。

String類是不可改變的量,也就是創建後就不能再修改了,比如創建了一個"abc"這樣的字符串對象,那麼它在內存中永遠都會是"abc"這樣具有固定表面值的一個對象,不能被修改,即使想通過String提供的方法來嘗試修改,也是要麼創建一個新的字符串對象,要麼返回自己,比如:


String str="abc";

String str1=str.substring(1);


其中,str是一個字符串對象,其值是"abc",通過substring方法又重新生成了一個字符串str1,它的值是"bc",也就是說str引用的對象一旦產生就永遠不會改變。為什麼上面還說有可能不創建對像而返回自己呢?那是因為採用str.substring(0)就不會創建新對象,JVM會從字符串池中返回str的引用,也就是自身的引用。

StringBuffer是一個可變字符序列,它與String一樣,在內存中保存的都是一個有序的字符序列(char類型的數組),不同點是StringBuffer對象的值是可改變的,例如:


StringBuffer sb=new StringBuffer("a");

sb.append("b");


從上面的代碼可以看出sb的值在改變,初始化的時候是"a",經過append方法後,其值變成了"ab"。可能有讀者會問了,這與String類通過「+」連接有什麼區別?例如:


String s="a";

s=s+"b";


有區別,字符串變量s初始化時是"a"對象的引用,經過加號計算後,s變量就修改為了"ab"的引用,但是初始化的"a"對像還是沒有改變,只是變量s指向了新的引用地址。再看看StringBuffer的對象,它的引用地址雖不變,但值在改變。

StringBuilder與StringBuffer基本相同,都是可變字符序列,不同點是:StringBuffer是線程安全的,StringBuilder是線程不安全的,翻翻兩者的源代碼,就會發現在StringBuffer的方法前都有synchronized關鍵字,這也是StringBuffer在性能上遠低於StringBuilder的原因。

在性能方面,由於String類的操作都是產生新的String對象,而StringBuilder和StringBuffer只是一個字符數組的再擴容而已,所以String類的操作要遠慢於StringBuffer和StringBuilder。

弄清楚了三者的原理,我們就可以在不同的場景下使用不同的字符序列了:

(1)使用String類的場景

在字符串不經常變化的場景中可以使用String類,例如常量的聲明、少量的變量運算等。

(2)使用StringBuffer類的場景

在頻繁進行字符串的運算(如拼接、替換、刪除等),並且運行在多線程的環境中,則可以考慮使用StringBuffer,例如XML解析、HTTP參數解析和封裝等。

(3)使用StringBuilder類的場景

在頻繁進行字符串的運算(如拼接、替換、刪除等),並且運行在單線程的環境中,則可以考慮使用StringBuilder,如SQL語句的拼裝、JSON封裝等。

注意 在適當的場景選用字符串類型。