2011-09-22 59 views
3

在應用程序中,字符串是一種常用的數據類型。我們知道的是,字符串的變化使用大量的內存。所以我們可以做的是使用一個StringBuilder/StringBuffer。我們應該什麼時候將字符串更改爲Stringbuilder?

但是我們應該在什麼時候改爲StringBuilder?
我們該怎麼做,當我們必須拆分它或重新放置那裏的角色時?

如:

//original: 
String[] split = string.split("?"); 
//better? : 
String[] split = stringBuilder.toString().split("?); 
String,那麼你可以去 StringBuilder

//original: 
String replacedString = string.replace("l","st"); 
//better? : 
String replacedString = stringBuilder.toString().replace("l","st"); 
//or 
StringBuilder replacedStringBuilder = new StringBuilder(stringBuilder.toString().replace("l","st); 
+4

如果您擔心這種侵入式重構,並且您不知道「StringBuilder」和'StringBuffer'(可能它們與'String'有什麼不同),你可能是做這種重構的錯誤人物。 –

+1

這是我的應用程序;)爲什麼其他人應該重構...否則當我不這樣做時,學習效果在哪裏? – Neifen

+0

好的。當你這樣做重構時,你將不得不改變你正在使用的很多API,因爲它們中的很多都需要'String'。您還應該多介紹一下您想要優化的字符串:它們是否僅用於應用程序的一小部分?整個系統的哪些組件需要它們,並且它們是否要求它們以'String'的形式傳遞? –

回答

1

我們知道,字符串的變異使用了大量的內存。

這是不正確的。字符串不能被突變。它們是不可改變的。

你實際上正在談論的是從其他字符串構建字符串。這可以使用比需要更多的內存,但它取決於如何你建立的字符串。

所以我們可以做的就是使用一個StringBuilder/StringBuffer。

使用一個StringBuilder會在某些情況下幫助:

String res = ""; 
    for (String s : ...) { 
     res = res + s; 
    } 

(如果循環迭代很多次,然後優化上面使用StringBuilder 可能是值得的。)

但在其他情況是浪費時間:

String res = s1 + s2 + s3 + s4 + s5; 

(因爲Java編譯器會自動將表達式轉換爲創建和使用StringBuilder的代碼,所以優化上述代碼是浪費時間。)

當應用程序使用StringBuilder時,您應該只使用StringBuffer而不是StringBuilder字符串需要被多個線程訪問和/或更新;即當它需要是線程安全的。

但是在什麼時候我們應該改爲StringBuilder?

簡單的答案是只有做時,探查告訴你您在字符串處理/處理有性能問題。

一般來說,StringBuilders用於建造字符串,而不是字符串的主要表示形式。

當我們需要拆分它或替換那裏的字符時,我們應該怎麼做?

然後,您必須檢查您決定使用StringBuilder/StringBuffer作爲您在此時的主要表示。如果仍然有保證,您必須弄清楚如何使用您選擇的API來執行操作。 (這可能需要轉換爲字符串,執行操作,然後從結果中創建一個新的StringBuilder。)

+0

+1非常廣泛,去我所有的問題一個thx – Neifen

1

如果你需要大量的alter操作的。如果您在多線程應用程序中,請致電StringBuffer

+0

爲什麼在多線程應用程序上更好地使用StringBuffer? – Neifen

+2

StringBuffer被設計爲線程安全的,並且StringBuffer中的所有公共方法都是同步的。所以它可以用於多線程應用程序。但儘可能使用新的'StringBuilder'。 – Vaandu

2

如果您經常修改字符串,請使用StringBuilder。否則,如果它是不可變的,請使用String

要回答你如何替換字符的問題,請查看:http://download.oracle.com/javase/tutorial/java/data/buffers.html。 StringBuilder操作就是你想要的。

這裏有StringBuilder另一個很好的寫了起來:http://www.yoda.arachsys.com/csharp/stringbuilder.html

+0

所以像我的第二個例子的替換是一個變種,不是嗎。但是採用'stringBuilder.toString()。replace(...);'並不會產生反作用,並且將它另存爲一個StringBuilder? – Neifen

+0

是的。所以如果你有很多這樣的替換,最好堅持使用'StringBuilder'。如果使用'String',對於每個變異,都會創建一個新的'String'對象 - 這是無效的內存管理。 – user183037

+0

那麼最佳解決方案是什麼?有沒有一種節省內存的可能性呢? – Neifen

6

在你的例子,也有使用StringBuilder沒有任何好處,因爲你使用toString方法創建一個不可改變的String你的StringBuilder的。

完成附加(或以其他方式修改)後,您應該只將StringBuilder的內容複製到String中。

Java的StringBuilder的問題在於,它缺少使用純字符串時的某些方法(請檢查此線程,例如:How to implement StringBuilder.replace(String, String))。

我們知道,一個字符串使用大量的內存。

實際上,準確地說,一個String使用比具有等效內容的StringBuilder更少存儲器。 A StringBuilder類有一些額外的常量開銷,並且通常有一個預分配的緩衝區來存儲比任何給定時刻需要的更多數據(以減少分配)。 String的問題在於它們是不可變的,這意味着無論何時需要更改其內容,Java都需要創建一個新實例。

總而言之,StringBuilder不是爲您提到的操作(拆分和替換)而設計的,並且在任何情況下都不會產生更好的性能。 split方法不能受益於StringBuilder的可變性,因爲它無論如何都會創建一個不可變字符串數組作爲其輸出。替換方法仍然需要遍歷整個字符串,並且如果替換的字符串與搜索的字符串的大小不一樣,則需要進行大量的複製。

如果你需要做很多追加,那麼去一個StringBuilder。由於它在引擎蓋下使用了「可變」字符數組,因此將數據添加到最後會特別有效。

This article比較了幾個StringBuilderString方法的性能(雖然我會採取與儲備級聯的部分,因爲它沒有提到動態串上追加和集中在只有一個Join操作)。

+1

好的我們知道的是,一個字符串的變化使用大量的內存 – Neifen

+0

+1來提及'String'使用比'StringBuilder'少的內存。我錯過了我的答案。 – user183037

+1

@ Neifen:String的變種創建一個新的String。這就是爲什麼它效率低下。另一方面,StringBuilder的變異不會創建一個新的StringBuilder。 – user183037

0

StringStringBuilder都使用大約相同數量的內存。你爲什麼認爲這「很」?

如果有測量(例如具有jmap -histo:live),所述類[Cjava.lang.String佔用在堆大部分內存,才應該你進一步認爲在這個方向。

也許有多個字符串具有相同的值。那麼,由於String是不可變的,所以你可以在實習生重複字符串。不要使用String.intern,因爲它具有糟糕的性能特徵,但Google Guava的Interner

+0

'String'確實使用比'StringBuilder'更少的內存。 – user183037

+0

那麼?我只是說他們使用*關於*相同數量的內存。我現在沒有可用的JVM來檢查一個String是否真的比StringBuilder少8個字節,但這似乎並不重要。如果OP擔心String已經使用了太多的內存,他不應該切換到StringBuilder,而是尋找替代方法。 –

+0

你做出了一個近似聲明,並繼續詳細說明與OP所要求的內容幾乎沒有關係的東西。 OP的問題顯而易見,他是Java的新手。當你談論實習生和番石榴的幹事時,你只是拋棄他,當然這不是他所問的。 我不是粗魯的,只是說明一個事實。無需投擲健身。 – user183037

相關問題