2011-09-28 23 views
47

據Netbeans的提示命名使用.append方法而不是字符串連接StringBuilder.append的鏈比字符串連接更有效嗎?

會在StringBuilder的或的StringBuffer的append方法的調用的參數字符串連接鏈。

是StringBuilder.append()真的比字符串連接更有效嗎?

代碼示例

StringBuilder sb = new StringBuilder(); 
sb.append(filename + "/"); 

StringBuilder sb = new StringBuilder(); 
sb.append(filename).append("/"); 
+0

看看這個有趣的閱讀:http://www.precisejava.com/javaperf/j2se/StringAndStringBuffer.htm – Zaki

+1

@Zaki:這些基準實際上並不是那麼有用。更有用的是分析你的應用程序,看它是否確實有性能瓶頸。併爲您的特定用例選擇適當的算法和數據結構。 – mellamokb

回答

69

你必須平衡可讀性和功能性。

比方說,你有以下幾種:

String str = "foo"; 
str += "bar"; 
if(baz) str += "baz"; 

這將創建2個字符串生成器(在這裏你只需要1,真的)加上臨時的額外字符串對象。你會更有效率,如果你去:

StringBuilder strBuilder = new StringBuilder("foo"); 
strBuilder.append("bar"); 
if(baz) strBuilder.append("baz"); 
String str = strBuilder.toString(); 

但作爲一種風格,我認爲第一個看起來就好。單個對象創建的性能優勢對我來說似乎很小。現在,如果不是3個字符串,而是10個,20個或100個,我會說性能超過這個風格。如果它是在一個循環中,肯定會使用字符串生成器,但我認爲只需幾個字符串就可以做到「馬虎」的方式,使代碼看起來更乾淨。但是......這有一個非常危險的陷阱潛藏在裏面!請閱讀下面的(暫停建立懸念... dun dun dunnnn)

有人說總是使用顯式字符串生成器。一個基本原理是你的代碼將繼續增長,並且通常會以與已經相同的方式這樣做(即他們不會花時間重構)。所以,最終你會得到10或20條語句,每條語句創建當你不需要時他們自己的建造者。所以爲了防止這種情況發生,他們總是使用一個明確的構建器。

因此,儘管在你的榜樣,它不會特別快,當有人在未來的決定,他們希望在末尾的文件擴展名,或者類似的東西,如果他們繼續使用,而不是一個StringBuilder字符串連接,他們最終會遇到性能問題。

我們還需要考慮未來。比方說,你做了Java代碼早在JDK 1.1和你有以下方法:

public String concat(String s1, String s2, String s3) { 
    return s1 + s2 + s3; 
} 

當時,那將是緩慢的,因爲StringBuilder的是不存在的。

然後在JDK 1.3中,您決定通過使用StringBuffer使其更快(StringBuilder仍然不存在)。你這樣做:

public String concat(String s1, String s2, String s3) { 
    StringBuffer sb = new StringBuffer(); 
    sb.append(s1); 
    sb.append(s2); 
    sb.append(s3); 
    return sb.toString(); 
} 

它變得更快。真棒!

現在JDK 1.5出來,和與之而來的StringBuilder(它比StringBuffer的更快)和

return s1 + s2 + s3; 

自動TRANSATION到

return new StringBuilder().append(s1).append(s2).append(s3).toString(); 

但你沒有得到這樣的性能因爲您明確使用了StringBuffer,因此受益匪淺。所以,通過聰明,當Java比你聰明時,你已經導致了性能的下降。所以你必須記住,有些事情你不會想到。

+0

@corsiKa:我的循環運行了16次,這就是我在循環中做的 - str + = som_value。我的是jdk1.6。所以我應該使用StringBuilder或不。 – Ashwin

+0

@Ashwin我個人會在那裏使用StringBuilder。有必要嗎?我想這取決於循環運行的頻率。如果你正在構建一個散列的輸出,那麼你可以期望做到這一點。絕對加快速度。如果你正在構建你的程序的標題,它只會被調用一次,可能不是什麼大不了的事情。 – corsiKa

2

這只是更有效率,如果你正在使用大量的串聯和很長的字符串。對於一般用途,比如在你的例子中創建一個文件名,任何字符串連接都很好,更具可讀性。

無論如何,這部分應用程序不太可能成爲性能瓶頸。

+1

+1,但我認爲總是創建StringBuilder對象 – gd1

10

好了,你的第一個例子基本上是由編譯器翻譯成東西沿着線:

StringBuilder sb = new StringBuilder(); 
sb.append(new StringBuilder().append(filename).append("/").toString()); 

所以是的,是有一定效率在這裏。但是,在你的程序中它是否真的很重要是一個不同的問題。除了有問題的風格(暗示:主觀)之外,如果你在緊密循環中這樣做,它通常只是很重要的。

+0

字符串連接實際上是否使用'StringBuilder'完成的?讓'String'包含一個接受兩個字符串並將它們連接起來的構造函數(可能也有3-4個字符串的版本,以及一個接受'String []'的版本)似乎更合理。如果要串聯字符串,可以在爲結果的後備存儲分配空間之前添加它們的長度,從而一次性分配恰當的空間量。編譯器不這樣做似乎很瘋狂。 – supercat

2

理論上,是的。因爲String對象是不可變的:一旦構造它們就不能再被改變。所以使用「+」(連接)基本上每次都會創建一個新對象。

實際上沒有。編譯器足夠聰明,可以用StringBuilder附錄替換所有的「+」。

對於更詳細的解釋: http://kaioa.com/node/59

PS:Netbeans的???來吧!

+0

'快點!'?那麼你會推薦什麼? –

+0

你的第二句暗示它們全部放入一個StringBuilder中。這是不準確的。如果你有'String s =「a」+「b」; s + =「c」;'你得到2個字符串構建器,而不是1 – corsiKa

+1

我會推薦intelliJ或者Eclipse – Guillaume

2

使用此功能,兩個字符串的串接更快。

但是,如果您有多個字符串或不同的數據類型,您應該明確或隱式地使用StringBuilder。使用帶有Strings的+隱式使用StringBuilder。

5

到目前爲止,沒有任何答案明確地解決提示的具體情況。這並不是說總是使用StringBuilder#append而不是拼接。但是,如果您已經使用StringBuilder,那麼混合拼接就沒有意義了,因爲它會創建多餘的StringBuilder(請參閱Dirk's answer)和不必要的臨時String實例。

幾個答案已經討論了爲什麼建議的方式更高效,但重點是,如果您已經有一個StringBuilder實例,只需撥打append就可以了。它是一樣可讀的(在我看來,顯然是誰寫的NetBeans提示),因爲無論如何你調用了append,而且效率更高一些。

+0

可能有些情況下,首先進行連接會有好處;大多數情況下,如果字符串的長度有一些隨機變化,則預串聯效率更高的可能性會非常低,但對於某些字符串長度的特定組合,它可能每次都會「贏」。如果第一個'Append'將'StringBuilder' /'StringBuffer'展開爲不足以容納第二個的大小,則由連接引起的額外分配可能比SB所使用的分配更便宜。罕見的情況,但可能的。 – supercat

+0

@supercat這是一個有趣的觀點,也是一個很好的例子,說明爲什麼在優化代碼(以及使用代表性數據)時應該始終進行測量。 –

+1

我自己的選擇是訴諸我的主要規則:「做什麼是有道理的」。在大多數情況下,不管哪種方式都不會出現巨大的性能差異,所以當它更清晰並且不太可能明顯影響性能時,支持並置。在多個連接必須出現在不同的語句中的情況下,我更喜歡'StringBuilder',但是當它們可以出現在一個表達式中時,我更喜歡這種情況。除非字符串很大,否則易讀性應優先於性能。 – supercat