40

Possible Duplicate:
StringBuilder vs String concatenation in toString() in Java

I am wondering, since the compiler internally uses a StringBuilder to append Strings when performing String concatenation, then what's the point and why should I bother using StringBuilder if String concatenation already did the job for you? Are there any other specific reasons?

Hearen
  • 6,019
  • 2
  • 36
  • 50
peter
  • 7,752
  • 16
  • 64
  • 89

2 Answers2

69

As you mention, you should not use StringBuilder instead of a simple string concatenation expression such as a + " = " + b. The latter is faster to type, easier to read, and the compiler will use a StringBuilder internally anyway so there is no performance advantage by rewriting it.

However StringBuilder is useful if you are concatenating a large number of strings in a loop. The following code is inefficient. It requires O(n2) time to run and creates many temporary strings.

String result = "";
for (int i = 0; i < foo.length; ++i)
{
    result += bar(foo[i]);  // Bad
}

Try this instead:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < foo.length; ++i)
{
    sb.append(bar(foo[i]));
}
String result = sb.toString();

The compiler optimises only simple a + b + c expressions. It cannot optimize the above code automatically.

Mark Byers
  • 719,658
  • 164
  • 1,497
  • 1,412
  • 4
    @JohanSjöberg yes, in fact it does. Doing `result += bar(foo[i])` will produce code like (assuming javac) `result = new StringBuilder().append(result).append(foo[i]).toString()`. Notice this is a whole lot more work than using one `StringBuilder`. – obataku Aug 13 '12 at 21:18
  • @JohanSjöberg the point is that __the samples are not equivalent__ – obataku Aug 13 '12 at 21:19
  • I am still not that clear why ?? Is it because it requires to copy over the old string (previous) before it does the concatenation for the first sample ? – peter Aug 13 '12 at 21:21
  • 3
    @user1389813: It's because in the first sample, Java's optimizer doesn't know how to retain one StringBuilder to do all that concatenation in the loop -- it doesn't see far enough ahead to know you'll always be concatenating to the same string that otherwise never sees the outside of the loop, so it creates a new one each time it has to add onto `result`. – cHao Aug 13 '12 at 21:23
  • 4
    @user1389813 using `+=` will create a new `StringBuilder` each iteration, copy the source string, append whatever you're concatenating (which could also require a copy), and then converting it into a `String` (which is another copy). Using one `StringBuilder` avoids unnecessary copying. – obataku Aug 13 '12 at 21:23
  • @cHao which optimizer? javac doesn't do an optimization pass anymore; optimizations are better suited at runtime during [compilation](http://en.wikipedia.org/wiki/Just-in-time_compilation). – obataku Aug 13 '12 at 21:24
  • 1
    what about result = result + bar(foo[i]); ? is that also ends up the same way ? – peter Aug 13 '12 at 21:28
  • @veer: *Some* optimizations are better done at runtime. This particular type isn't really doable unless the compiler (or programmer!) does it, as creating new objects can have side effects that an optimizer shouldn't eliminate (and couldn't even reliably predict without solving the Halting Problem). – cHao Aug 13 '12 at 21:31
  • 2
    @cHao yes, I'm fully aware of theory -- but I'm discussing the actual compiler at hand (presuming it is javac). javac does not explicitly perform any *real* optimizations anymore, and it never did ones that complex. The ones that it does are constant folding and a DCE pass. – obataku Aug 13 '12 at 21:36
3

Where are you assuming that string concatination uses stringbuilder internally? Maybe a simple concat gets optimized away, but this will definitely not:

String s = "";

for (int i = 0; i < 1000; i++){
  for (int j = 0; j < 1000; j++){
    s+= "" + i + j
}
}
Falmarri
  • 44,586
  • 38
  • 140
  • 186
  • 1
    So what will this be internally ? – peter Aug 13 '12 at 21:14
  • @user1389813 `s = new StringBuilder.append("").append(i).append(j).toString();` presuming the compiler is javac. – obataku Aug 13 '12 at 21:19
  • so each time it will create a new StringBuilder to perform the concatenation, so that's why it's bad and slow, correct ? – peter Aug 13 '12 at 21:25
  • 1
    I wouldn't say it's necessarily *slow* (I don't advocate premature optimization)... it's just not a good habit. – obataku Aug 13 '12 at 21:26
  • @user1389813 It's not just that it creates a new StringBuilder, it's that it creates a new StringBuilder, then copies all of the chars from the `s` string, and only *then* appends `i` and `j`. Each loop, you're copying all of the chars you had previously (which themselves have been copied from previous loops), giving you O(n^2) performance. By removing the new StringBuilder from the loop body, you eliminate all of that redundant copying. – yshavit Aug 13 '12 at 21:35