Why to Use Stringbuffer in Java Instead of the String Concatenation Operator

what is the significance of StringBuffer and which should be used more often, StringBuffer or StringBuilder?

In practice everybody should always use StringBuilder (and never use StringBuffer; often you don't really need StringBuilder because the compiler takes care of adding a helper to do this for you). The only reason StringBuffer is still around is for fear that taking it away would break some code somewhere. Java takes backward compatibility really seriously.

The difference between StringBuffer and StringBuilder is that the methods of StringBuffer are synchronized. That means each thread trying to call a synchronized method has to acquire the lock on the object, this prevents problems where two threads calling methods on the same object could result in the object's state becoming corrupted. The backing data store within the object is a dynamically-growing array, and if two threads are messing with it at the same time and one changes it out from under the other, bad things happen: exceptions get thrown, or worse, data gets stomped on silently.

It turns out that there is not a real life need for a string-building object that concatenates strings received concurrently from multiple threads, because nobody wants a string constructed in a way that makes it unpredictable what order the substrings show up in. It's overwhelmingly likely that when you want to construct a string (and have determined you do need a builder) that builder will be thread-confined (meaning only one thread can access the builder), so no synchronization is needed.

StringBuilder vs String concatenation in toString() in Java

Version 1 is preferable because it is shorter and the compiler will in fact turn it into version 2 - no performance difference whatsoever.

More importantly given we have only 3
properties it might not make a
difference, but at what point do you
switch from concat to builder?

At the point where you're concatenating in a loop - that's usually when the compiler can't substitute StringBuilder by itself.

StringBuilder/StringBuffer vs. + Operator

Using String concatenation is translated into StringBuilder operations by the compiler.

To see how the compiler is doing I'll take a sample class, compile it and decompile it with jad to see what's the generated bytecode.

Original class:

public void method1() {
System.out.println("The answer is: " + 42);
}

public void method2(int value) {
System.out.println("The answer is: " + value);
}

public void method3(int value) {
String a = "The answer is: " + value;
System.out.println(a + " what is the question ?");
}

The decompiled class:

public void method1()
{
System.out.println("The answer is: 42");
}

public void method2(int value)
{
System.out.println((new StringBuilder("The answer is: ")).append(value).toString());
}

public void method3(int value)
{
String a = (new StringBuilder("The answer is: ")).append(value).toString();
System.out.println((new StringBuilder(String.valueOf(a))).append(" what is the question ?").toString());
}
  • On method1 the compiler performed the operation at compile time.
  • On method2 the String concatenation is equivalent to manually use StringBuilder.
  • On method3 the String concatenation is definitely bad as the compiler is creating a second StringBuilder rather than reusing the previous one.

So my simple rule is that concatenations are good unless you need to concatenate the result again: for instance in loops or when you need to store an intermediate result.

String concatenation in Java - when to use +, StringBuilder and concat

I tend to use StringBuilder on code paths where performance is a concern. Repeated string concatenation within a loop is often a good candidate.

The reason to prefer StringBuilder is that both + and concat create a new object every time you call them (provided the right hand side argument is not empty). This can quickly add up to a lot of objects, almost all of which are completely unnecessary.

As others have pointed out, when you use + multiple times within the same statement, the compiler can often optimize this for you. However, in my experience this argument doesn't apply when the concatenations happen in separate statements. It certainly doesn't help with loops.

Having said all this, I think top priority should be writing clear code. There are some great profiling tools available for Java (I use YourKit), which make it very easy to pinpoint performance bottlenecks and optimize just the bits where it matters.

P.S. I have never needed to use concat.

When to use StringBuilder in Java

If you use String concatenation in a loop, something like this,

String s = "";
for (int i = 0; i < 100; i++) {
s += ", " + i;
}

then you should use a StringBuilder (not StringBuffer) instead of a String, because it is much faster and consumes less memory.

If you have a single statement,

String s = "1, " + "2, " + "3, " + "4, " ...;

then you can use Strings, because the compiler will use StringBuilder automatically.

String concatenation with operator + vs using stringbuffer?

First notice that the documentation you have linked is very old. Notice it's for Java 1.4.2.

J2SE 1.4.2 is in its Java Technology End of Life (EOL) transition period. The EOL transition period began Dec, 11 2006 and will complete October 30th, 2008, when J2SE 1.4.2 will have reached its End of Service Life (EOSL).

In newer versions of the documentation this statement has been removed. However another statement has been added that you should be aware of:

As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.


Secondly notice that the documentation you refer to has this code:

x = "a" + 4 + "c";

The 4 there isn't just a typo. Your example is different because the compiler will convert the code to use just a single string literal. These two lines are the same:

x = "a" + "b" + "c"; 
x = "abc";

The string literal will be interned.


But in the general case where the compiler cannot just use a single string literal, the compiler will transform the first version into the second, except it will use StringBuilder instead because it is more efficient.

String concatenation: concat() vs + operator

No, not quite.

Firstly, there's a slight difference in semantics. If a is null, then a.concat(b) throws a NullPointerException but a+=b will treat the original value of a as if it were null. Furthermore, the concat() method only accepts String values while the + operator will silently convert the argument to a String (using the toString() method for objects). So the concat() method is more strict in what it accepts.

To look under the hood, write a simple class with a += b;

public class Concat {
String cat(String a, String b) {
a += b;
return a;
}
}

Now disassemble with javap -c (included in the Sun JDK). You should see a listing including:

java.lang.String cat(java.lang.String, java.lang.String);
Code:
0: new #2; //class java/lang/StringBuilder
3: dup
4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
7: aload_1
8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
12: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/ String;
18: astore_1
19: aload_1
20: areturn

So, a += b is the equivalent of

a = new StringBuilder()
.append(a)
.append(b)
.toString();

The concat method should be faster. However, with more strings the StringBuilder method wins, at least in terms of performance.

The source code of String and StringBuilder (and its package-private base class) is available in src.zip of the Sun JDK. You can see that you are building up a char array (resizing as necessary) and then throwing it away when you create the final String. In practice memory allocation is surprisingly fast.

Update: As Pawel Adamski notes, performance has changed in more recent HotSpot. javac still produces exactly the same code, but the bytecode compiler cheats. Simple testing entirely fails because the entire body of code is thrown away. Summing System.identityHashCode (not String.hashCode) shows the StringBuffer code has a slight advantage. Subject to change when the next update is released, or if you use a different JVM. From @lukaseder, a list of HotSpot JVM intrinsics.

Why String concatenation is faster than StringBuilder in Java?

I expected the byte code of formatRich and formatFine were equivalent, yet it was not. So I tried to get two equivalent methods:

Rewrite your StringBuilder method to

public static String formatFine(Address obj) {
return new StringBuilder("<div class=\"address-wrapper\">\n\t<div class=\"addr-line\">")
.append(obj.getLine1())
.append("</div>\n\t<div class=\"addr-line\">")
.append(obj.getLine2())
.append("</div>\n\t<div class=\"addr-city\">")
.append(obj.getCity())
.append("</div>\n\t<div class=\"addr-state\">")
.append(obj.getState())
.append("</div>\n\t<div class=\"addr-country\">")
.append(obj.getCountry())
.append("</div>\n\t<div class=\"addr-zip\">")
.append(obj.getZip())
.append("</div>\n</div>\n").toString();
}

This method is equivalent to following in java byte code:

public static String formatRich(Address obj) {
return "<div class=\"address-wrapper\">\n\t<div class=\"addr-line\">"
+ obj.getLine1()
+ "</div>\n\t<div class=\"addr-line\">"
+ obj.getLine2()
+ "</div>\n\t<div class=\"addr-city\">"
+ obj.getCity()
+ "</div>\n\t<div class=\"addr-state\">"
+ obj.getState()
+ "</div>\n\t<div class=\"addr-country\">"
+ obj.getCountry()
+ "</div>\n\t<div class=\"addr-zip\">"
+ obj.getZip()
+ "</div>\n</div>\n";
}

Executing your main program resolves (on my machine) to:

...

Test cases: 10000000
Average time to format (SB Poor): 633 ns
Average time to format (SB Fine): 151 ns
Average time to format (String) : 152 ns

Explanation:

  • The explicit statement str.append has to load str from the stack. The result is pushed on the stack but never used.
  • The direct concatenation (and the chained StringBuilder) reuses the result of str.append which is already on the stack
  • Both (str and the result of str.append) point to the same heap location, yet I do not know if this can be derived by the compiler. It seems that the current optimization level is not able to optimize it.

Where to use StringBuffer/StringBuilder than String

Below is the main difference between these three most commonly used classes.

  • String class objects are immutable whereas StringBuffer and
    StringBuilder objects are mutable.
  • StringBuffer is synchronized while StringBuilder is not synchronized.
  • Concatenation operator "+" is internal implemented using either
    StringBuffer or StringBuilder.

Criteria to choose among String, StringBuffer and StringBuilder

  • If the Object value is not going to change use String Class because a
    String object is immutable.
  • If the Object value can change and will only be accessed from a
    single thread, use a StringBuilder because StringBuilder is
    unsynchronized.
  • In case the Object value can change, and will be modified by multiple
    threads, use a StringBuffer because StringBuffer is synchronized.


Related Topics



Leave a reply



Submit