74

I am little confused about using StringBuilder class, first:

A string object concatenation operation always creates a new object from the existing string and the new data. A StringBuilder object maintains a buffer to accommodate the concatenation of new data. New data is appended to the end of the buffer if room is available; otherwise, a new, larger buffer is allocated, data from the original buffer is copied to the new buffer, then the new data is appended to the new buffer.

But where is the point of creating StringBuilder instance to avoid creating new one of String? It sounds like trading "one for one".

static void Main(string[] args)
{
    String foo = "123";
    using (StringBuilder sb = new StringBuilder(foo)) // also sb isn't disposable, so there will be error
    {
        sb.Append("456");
        foo = sb.ToString();
    }

    Console.WriteLine(foo);
    Console.ReadKey();
}

Why I shouldn't just use

+=

Edit: Ok, I know now how to reuse one instance of StringBuilder (still don't know if this is right with code standards), but this isn't worth to use with just one string, isn't it?

Bartłomiej Sobieszek
  • 2,692
  • 2
  • 25
  • 40
  • 5
    http://www.dotnetperls.com/stringbuilder-performance versus http://www.dotnetperls.com/string-concat – Steve Feb 08 '14 at 10:17
  • 1
    @royB What does "string contention uses stringbuilder (str1 + str2) natively" mean? String *concatenation* does in fact *not* use StringBuilder internally. – Lasse V. Karlsen Feb 08 '14 at 10:22

3 Answers3

113

Modifying immutable structures like strings must be done by copying the structure, and by that, consuming more memory and slowing the application's run time (also increasing GC time, etc...).

StringBuilder comes to solve this problem by using the same mutable object for manipulations.

However:

when concatenating a string in compile time as the following:

string myString = "123";
myString += "234";
myString += "345";

it will actually compile to something like that:

string myString = string.Concat("123", "234", "345");

this function is faster than working with StringBuilder for the number of strings entering the function is known.

so for compile-time-known string concatenations you should prefer string.Concat().

as for unknown number of string like in the following case:

string myString = "123";
if (Console.ReadLine() == "a")
{
    myString += "234";
}
myString += "345";

Now the compiler can't use the string.Concat() function, however, StringBuilder appears to be more efficient in time and memory consumption only when the concatenation is done with 6-7 or more strings.

Bad practice usage:

StringBuilder myString = new StringBuilder("123");
myString.Append("234");
myString.Append("345");

Fine practice usage (note that if is used):

StringBuilder myString = new StringBuilder("123");
if (Console.ReadLine() == "a")
{
    myString.Append("234");
}
myString.Append("345");

Best practice usage (note that while loop is used):

StringBuilder myString = new StringBuilder("123");
while (Console.ReadLine() == "a")
{
    myString.Append("234"); //Average loop times 4~ or more
}
myString.Append("345");
Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
  • Aren't your last two examples exactly the same? – Jaimie Knox Dec 30 '16 at 17:48
  • 2
    @JaimieKnox note the `while`/`if` and the comment. – Tamir Vered Dec 30 '16 at 18:03
  • 4
    Ah thank you. I must have read that 100 times and still missed it. – Jaimie Knox Dec 30 '16 at 18:19
  • What if you're concatenating in a `for` loop for each item in a list? Will `+=` compile to: `string.concatenate(a,b,...,z)`? If so, do you use a `StringBuilder` if there are ~4 or more items in the list? – monster Feb 06 '17 at 16:11
  • 1
    @monster It won't be compiled to `string.Concat` (between all of the `strings` in the `List` at one time) since the compiler can't assume anything about the `strings` in the `List`, therefore, if you assume there will be more than a few concatenations - `StringBuilder` should be used. – Tamir Vered Feb 06 '17 at 16:17
13

A string is an immutable class. You cannot modify it, only create new strings.

So when you write result += a; you have three separate strings in memory at that point: a, the old value of result and the new value. Of course this is absolutely fine if you only concatenate a limited number of strings. If you do that in a for loop iterating over a large collection it can become a problem.

The StringBuilder class offers improved performance in these cases. Instead of creating new strings to store the result of the concatenation it uses the same object. So if you use stringBuilder.Append(a); you never have the equivalent of the "old value of result".


This memory efficiency comes with a price of course. When only concatenating a small number of strings a StringBuilder is often less efficienct with regards to speed since it had more overhead compared to the immutable string class.


One thing to keep in mind is that when you need the intermediate strings then StringBuilder can become less efficient since calling .ToString() on it creates a new copy of the string.

Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
Dirk
  • 10,668
  • 2
  • 35
  • 49
3

The reason is because strings are immutable. When concatenating a string you create a new string. So, when you need to concatenate many strings you create a lot of objects. This doesn't cost much in terms of memory, as each string is used once. But it does give extra work for the GC.

StringBuilder however uses the same object each time, but it does so at the expense of ease of use.

Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
Aron
  • 15,464
  • 3
  • 31
  • 64