When you need to create strings dynamically, what should you use performance wise, String or StringBuffer? I thought StringBuffer performs better than String. So I always start with a StringBuffer, and after completing the String, return a buffer.toString().
The answer to your question depends on the nature of the string. If it is immutable (that is, unchangeable), use String. You could use StringBuffer, but doing so would allow code to directly change the immutable string's characters, and the string would no longer be immutable. Similarly, if the string is mutable, use StringBuffer. You could use String, but then you would end up creating additional String objects during string modification—because String methods that could potentially modify a string create additional String objects that contain modified strings. Eventually, the garbage collector would see the additional (and probably unreferenced) Strings and perform a collection—possibly affecting the program's performance. StringBuffer does not suffer from that performance problem because it does not create additional StringBuffer (or String) objects. Additional Strings that arise from using String (instead of StringBuffer) to represent a mutable string are one performance problem. A second problem, which can prove just as serious, could occur when you use StringBuffer to represent a mutable string. StringBuffer's character array (which holds a mutable string) has finite length. Any modification that results in a mutable string whose length exceeds the character array's length causes StringBuffer to create a new character array of appropriate length, copy characters from the old character array to the new character array, and erase the reference to the old character array (making that character array eligible for garbage collection). Because array creation, array copying, and garbage collection take time, how do you solve this potential performance problem? Either create a StringBuffer object with large enough initial capacity—character array length—or call StringBuffer's ensureCapacity() method to set an appropriate character array length prior to changing the array. That way, you minimize the number of extra activities. Both performance problems manifest themselves during looped string concatenation. Consider the following code fragment:
String s = "a";
for (int i = 0; i < 2000; i++)
s = s + "b";.
The code fragment translates into this byte code equivalent:
String s = "a";
for (int i = 0; i < 2000; i++)
s = new StringBuffer ().append (s).append ("b").toString ();
The code fragment above creates a StringBuffer and a String (via toString()) during each loop iteration. These objects are temporary and disappear after each loop iteration (although the last-created String is still referenced after the loop completes). Eventually, the garbage collector will probably run. How do you solve this potential performance problem? Consider the following code fragment:
String s = "a";
StringBuffer sb = new StringBuffer (2500); // Assume a maximum character array length of 2500 characters.
sb.append (s);
for (int i = 0; i < 2000; i++)
sb.append ("b");
s = sb.toString ();
The code fragment does not create any StringBuffer or String objects during the loop. Therefore, the potential for garbage collection is quite low. (Garbage collection can still occur because the garbage collector thread runs at various times and there may be unreferenced objects from previously-executed code to collect.) To sum up, understanding whether strings should be immutable or mutable will lead you to select the appropriate String/StringBuffer classes, which benefits performance. Furthermore, performance improves when you set an appropriate StringBuffer capacity prior to making many modifications and use care when dealing with looped string concatenation.
No comments:
Post a Comment