天天看點

Java:String、StringBuffer和StringBuilder的差別

1 String

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

/** The value is used for character storage. */
private final char value[];
 
/** The offset is the first index of the storage that is used. */
private final int offset;
 
/** The count is the number of characters in the String. */
private final int 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 的一個簡易替換,用在字元串緩沖區被單個線程使用的時候(這種情況很普遍)。

4 三者差別

String 類型和StringBuffer的主要性能差別:String是不可變的對象, 是以在每次對String 類型進行改變的時候,都會生成一個新的 String 對象,然後将指針指向新的 String 對象,是以經常改變内容的字元串最好不要用 String ,因為每次生成對象都會對系統性能産生影響,特别當記憶體中無引用對象多了以後, JVM 的 GC 就會開始工作,性能就會降低。

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

在某些特别情況下, String 對象的字元串拼接其實是被 Java Compiler 編譯成了 StringBuffer 對象的拼接,是以這些時候 String 對象的速度并不會比 StringBuffer 對象慢,例如:

String s1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
           

生成 String s1對象的速度并不比 StringBuffer慢。其實在Java Compiler裡,自動做了如下轉換:

Java Compiler 直接把上述第一條語句編譯為:

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

String s2 = “This is only a”;
String s3 = “ simple”;
String s4 = “ test”;
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的優化上是一條比較重要的原則。

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

(4)StringBuilder一般使用在方法内部來完成類似"+"功能,因為是線程不安全的,是以用完以後可以丢棄。StringBuffer主要用在全局變量中。

(5)相同情況下使用 StringBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。而在現實的子產品化程式設計中,負責某一子產品的程式員不一定能清晰地判斷該子產品是否會放入多線程的環境中運作,是以:除非确定系統的瓶頸是在 StringBuffer 上,并且确定你的子產品不會運作在多線程模式下,才可以采用StringBuilder;否則還是用StringBuffer。

參考資料:

http://docs.oracle.com/javase/tutorial/java/data/buffers.html

http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4