1. 程式人生 > >Java:String、StringBuffer和StringBuilder的區別與使用。

Java:String、StringBuffer和StringBuilder的區別與使用。

1 String

String:字串常量,字串長度不可變。Java中String是immutable(不可變)的。

String類的包含如下定義:

  1. /** The value is used for character storage. */
  2. privatefinalchar value[];  
  3. /** The offset is the first index of the storage that is used. */
  4. privatefinalint offset;  
  5. /** The count is the number of characters in the String. */
  6. private
    finalint count;  
用於存放字元的陣列被宣告為final的,因此只能賦值一次,不可再更改。

2 StringBuffer(JDK1.0)

StringBuffer:字串變數(Synchronized,即執行緒安全)。如果要頻繁對字串內容進行修改,出於效率考慮最好使用StringBuffer,如果想轉成String型別,可以呼叫StringBuffer的toString()方法。

Java.lang.StringBuffer執行緒安全的可變字元序列。在任意時間點上它都包含某種特定的字元序列,但通過某些方法呼叫可以改變該序列的長度和內容。可將字串緩衝區安全地用於多個執行緒。

StringBuffer 上的主要操作是 append 和 insert 方法,可過載這些方法,以接受任意型別的資料。每個方法都能有效地將給定的資料轉換成字串,然後將該字串的字元追加或插入到字串緩衝區中。append 方法始終將這些字元新增到緩衝區的末端;而 insert 方法則在指定的點新增字元。例如,如果 z 引用一個當前內容是“start”的字串緩衝區物件,則此方法呼叫 z.append("le") 會使字串緩衝區包含“startle”,而 z.insert(4, "le") 將更改字串緩衝區,使之包含“starlet”。

3 StringBuilder(JDK5.0)

StringBuilder:字串變數(非執行緒安全)。在內部,StringBuilder物件被當作是一個包含字元序列的變長陣列。

java.lang.StringBuilder是一個可變的字元序列,是JDK5.0新增的。此類提供一個與 StringBuffer 相容的 API,但不保證同步。該類被設計用作 StringBuffer 的一個簡易替換,用在字串緩衝區被單個執行緒使用的時候(這種情況很普遍)。

其構造方法如下:

構造方法 描述
StringBuilder() 建立一個容量為16的StringBuilder物件(16個空元素)
StringBuilder(CharSequence cs) 建立一個包含cs的StringBuilder物件,末尾附加16個空元素
StringBuilder(int initCapacity) 建立一個容量為initCapacity的StringBuilder物件
StringBuilder(String s) 建立一個包含s的StringBuilder物件,末尾附加16個空元素

在大部分情況下,StringBuilder > StringBuffer。這主要是由於前者不需要考慮執行緒安全。

4 三者區別

String 型別和StringBuffer的主要效能區別:String是不可變的物件, 因此在每次對String 型別進行改變的時候,都會生成一個新的 String 物件,然後將指標指向新的 String 物件,所以經常改變內容的字串最好不要用 String ,因為每次生成物件都會對系統性能產生影響,特別當記憶體中無引用物件多了以後, JVM 的 GC 就會開始工作,效能就會降低。

使用 StringBuffer 類時,每次都會對 StringBuffer 物件本身進行操作,而不是生成新的物件並改變物件引用。所以多數情況下推薦使用 StringBuffer ,特別是字串物件經常改變的情況下。

在某些特別情況下, String 物件的字串拼接其實是被 Java Compiler 編譯成了 StringBuffer 物件的拼接,所以這些時候 String 物件的速度並不會比 StringBuffer 物件慢,例如:

  1. String s1 = “This is only a” + “ simple” + “ test”;  
  2. StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);  
生成 String s1物件的速度並不比 StringBuffer慢。其實在Java Compiler裡,自動做了如下轉換:
Java Compiler直接把上述第一條語句編譯為:
  1. String s1 = “This is only a simple test”;  

所以速度很快。但要注意的是,如果拼接的字串來自另外的String物件的話,Java Compiler就不會自動轉換了,速度也就沒那麼快了,例如:

  1. String s2 = “This is only a”;  
  2. String s3 = “ simple”;  
  3. String s4 = “ test”;  
  4. String s1 = s2 + s3 + s4;  

這時候,Java Compiler會規規矩矩的按照原來的方式去做,String的concatenation(即+)操作利用了StringBuilder(或StringBuffer)的append方法實現,此時,對於上述情況,若s2,s3,s4採用String定義,拼接時需要額外建立一個StringBuffer(或StringBuilder),之後將StringBuffer轉換為String;若採用StringBuffer(或StringBuilder),則不需額外建立StringBuffer。

5 使用策略

(1)基本原則:如果要操作少量的資料,用String ;單執行緒操作大量資料,用StringBuilder ;多執行緒操作大量資料,用StringBuffer。

(2)不要使用String類的"+"來進行頻繁的拼接,因為那樣的效能極差的,應該使用StringBuffer或StringBuilder類,這在Java的優化上是一條比較重要的原則。例如:

  1. String result = "";  
  2. for (String s : hugeArray) {  
  3.     result = result + s;  
  4. }  
  5. // 使用StringBuilder
  6. StringBuilder sb = new StringBuilder();  
  7. for (String s : hugeArray) {  
  8.     sb.append(s);  
  9. }  
  10. String result = sb.toString();  
當出現上面的情況時,顯然我們要採用第二種方法,因為第一種方法,每次迴圈都會建立一個String result用於儲存結果,除此之外二者基本相同(對於jdk1.5及之後版本

(3)為了獲得更好的效能,在構造 StirngBuffer 或 StirngBuilder 時應儘可能指定它們的容量。當然,如果你操作的字串長度(length)不超過 16 個字元就不用了,當不指定容量(capacity)時預設構造一個容量為16的物件。不指定容量會顯著降低效能。

(4)StringBuilder一般使用在方法內部來完成類似"+"功能,因為是執行緒不安全的,所以用完以後可以丟棄。StringBuffer主要用在全域性變數中。

(5)相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的效能提升,但卻要冒多執行緒不安全的風險。而在現實的模組化程式設計中,負責某一模組的程式設計師不一定能清晰地判斷該模組是否會放入多執行緒的環境中執行,因此:除非確定系統的瓶頸是在 StringBuffer 上,並且確定你的模組不會執行在多執行緒模式下,才可以採用StringBuilder;否則還是用StringBuffer。

參考資料:

Java API