2010-07-19 35 views
5

我讀了很多關於如何使用StringBuffer和String的問題,特別是在Java中關聯連接以及線程安全與否的情況下。在Java中使用String或StringBuffer:哪個更好?

那麼,在各種Java方法中,應該使用哪種?

例如,在一個PreparedStatement,應查詢是一個StringBuffer:

String query = ("SELECT * " + 
        "FROM User " + 
        "WHERE userName = ?;"); 

    try { 
     ps = connection.prepareStatement(query); 

再然後,在一個字符串的實用方法,如:

public static String prefixApostrophesWithBackslash(String stringIn) { 
    String stringOut = stringIn.replaceAll("'", "\\\\'"); 
    return stringOut; 
} 

和:

// Removes a char from a String. 
public static String removeChar(String stringIn, char c) { 
    String stringOut = (""); 
    for (int i = 0; i < stringIn.length(); i++) { 
     if (stringIn.charAt(i) != c) { 
      stringOut += stringIn.charAt(i); 
     } 
    } 
    return stringOut; 
} 

我應該使用StringBuffers嗎?特別是repalceAll無法用於這些對象的情況。

謝謝

摩根先生。

感謝您的所有建議。 StringBuffers已被替換爲StringBuilders,而String替換爲StringBuilders,我認爲它是最好的。

回答

7

你幾乎從不需要使用StringBuffer

而不是StringBuffer你可能意味着StringBuilder。一個StringBuffer就像一個StringBuilder,除了它還提供線程安全性。這種線程安全在實踐中很少需要,只會導致代碼運行速度更慢。

你的問題似乎並不是關於String vs StringBuffer,而是關於使用內置方法或自己實現代碼。如果有一種內置的方法可以完全符合你的要求,那麼你應該使用它。它有可能比你寫的代碼更好的優化。

+1

我希望在第一個例子中沒有StringBuilder在內部使用,相反,編譯器可以將字符串連接成一個字符串,因爲沒有可變性。 – 2010-07-19 07:30:37

+0

這是一個非常好的點...刪除了那一點。 – 2010-07-19 07:35:26

+0

但是,鑑於此PreparedStatement可用於多線程場景中,不會使用StringBuffer更好嗎? – 2010-07-19 07:37:28

1

對於代碼

// Removes a char from a String. 
public static String removeChar(String stringIn, char c) { 
    String stringOut = (""); 
    for (int i = 0; i < stringIn.length(); i++) { 
     if (stringIn.charAt(i) != c) { 
      stringOut += stringIn.charAt(i); 
     } 
    } 
    return stringOut; 
} 

下面的部分你可以只是做stringIn.replaceAll(c+"","")

0

對於這可以被認爲是單線程的情況下,最好是StringBuilder。它不會增加任何同步開銷,而StringBuffer會這樣做。

僅當您懶惰地使用StringBuilder或者只是想讓代碼易於閱讀並且從性能的角度來看它是可以接受的時候,通過'+'運算符進行字符串連接是「好的」,就像在啓動日誌消息「LOG .info(「+ app_name)的啓動實例+ inst_id +」;「

+0

實際上,在絕大多數情況下,編譯器會將第二種形式轉換爲StringBuilder調用序列。因此,通常情況下,使用字符串連接來處理示例中給出的內容會更好**,因爲它更簡潔。你可以使用StringBuilder來處理任何你不直接拼接在一起的東西;例如在循環中,或者在函數調用之間傳遞構建器時。 – 2010-07-19 07:42:16

+0

@Andrzej Doyle - 實際上,我在我的例子中建議使用字符串連接。評論前請仔細閱讀。 – bobah 2010-07-19 21:15:24

+0

是的,但您的第二段暗示性能較差。我的觀點是,在大多數情況下(concantenation操作是詞法靜態的),編譯器將把它變成StringBuilder相當於bytecode *無論如何*。所以你得到你的蛋糕,吃它,這不是我給你的印象。 – 2010-07-20 07:38:24

1

即使在MT代碼中,有多個線程將東西附加到字符串也是不尋常的。 StringBuilder幾乎總是比StringBuffer更受歡迎。

3

沒有簡單的答案(除了重複StringBuilderStringBuffer之間的關係......)。爲了選擇最有效的解決方案,您真的瞭解一些關於「底層」情況的內容。

在你的第一個例子中,String是要走的路。對於由一系列字符串連接組成的任何表達式,Java編譯器可以生成非常優化的代碼(如有必要,使用StringBuilder)。而且,如果連接的字符串都是常量或文字,編譯器實際上可以在編譯時進行連接。

在第二個例子中,StringStringBuilder是否會更好......或者它們是否大致相等並不完全清楚。你需要看看java.util.regex.Matcher這個類的代碼。

編輯 - 我看了一下代碼,實際上它使用String或StringBuilder作爲源代碼沒有多大區別。 Matcher.replaceAll方法在內部創建一個新的StringBuilder,並通過追加源字符串和替換字符串中的塊來填充它。

在你的第三個例子中,StringBuilder顯然是最好的。當前代Java編譯器無法優化代碼(按照書寫)以避免在添加每個字符時創建新的String。

1

現代編譯器已經優化了代碼。所以一些String增加將會被優化以使用StringBuilder,並且如果我們認爲可以保持String增加,它會增加可讀性。

實施例1:

String query = ("SELECT * " + 
       "FROM User " + 
       "WHERE userName = ?;"); 

將被優化以財產以後像:

StringBuiler sb = new StringBuilder(); 
sb.append("SELECT * "); 
sb.append("FROM User "); 
sb.append("WHERE userName = ?;"); 
String query = sb.toString(); 

實施例2:

String numbers = ""; 
for (int i = 0;i < 20; i++) 
    numbers = numbers + i; 

這不能被優化,我們應該使用Strin gBuilder代碼。


我對SUN jdk1.5 +做了這個觀察。所以對於較舊的Java版本或不同的jdks,它可能會有所不同。在那裏它可以被保存爲總是編碼StringBuilder(或用於jdk 1.4.2和更舊版本的StringBuffer)。

+2

實際上,當連接字符串常量時,編譯器會將其優化爲單個字符串常量。 – ILMTitan 2010-07-19 14:29:19