Why to use StringBuffer in Java instead of the string concatenation operator

Someone told me it's more efficient to use StringBuffer to concatenate strings in Java than to use the + operator for Strings. What happens under the hood when you do that? What does StringBuffer do differently?


Solution 1:

It's better to use StringBuilder (it's an unsynchronized version; when do you build strings in parallel?) these days, in almost every case, but here's what happens:

When you use + with two strings, it compiles code like this:

String third = first + second;

To something like this:

StringBuilder builder = new StringBuilder( first );
builder.append( second );
third = builder.toString();

Therefore for just little examples, it usually doesn't make a difference. But when you're building a complex string, you've often got a lot more to deal with than this; for example, you might be using many different appending statements, or a loop like this:

for( String str : strings ) {
  out += str;
}

In this case, a new StringBuilder instance, and a new String (the new value of out - Strings are immutable) is required in each iteration. This is very wasteful. Replacing this with a single StringBuilder means you can just produce a single String and not fill up the heap with Strings you don't care about.

Solution 2:

For simple concatenations like:

String s = "a" + "b" + "c";

It is rather pointless to use StringBuffer - as jodonnell pointed out it will be smartly translated into:

String s = new StringBuffer().append("a").append("b").append("c").toString();

BUT it is very unperformant to concatenate strings in a loop, like:

String s = "";
for (int i = 0; i < 10; i++) {
    s = s + Integer.toString(i);
}

Using string in this loop will generate 10 intermediate string objects in memory: "0", "01", "012" and so on. While writing the same using StringBuffer you simply update some internal buffer of StringBuffer and you do not create those intermediate string objects that you do not need:

StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
    sb.append(i);
}

Actually for the example above you should use StringBuilder (introduced in Java 1.5) instead of StringBuffer - StringBuffer is little heavier as all its methods are synchronized.