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
theString
concatenation is equivalent to manually useStringBuilder
. - On
method3
theString
concatenation is definitely bad as the compiler is creating a secondStringBuilder
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 String
s, 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 loadstr
from the stack. The result is pushed on the stack but never used. - The direct concatenation (and the chained
StringBuilder
) reuses the result ofstr.append
which is already on the stack - Both (
str
and the result ofstr.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
Using Jasperreports with a Relative Path
Date Format Parse Exception - "Eee Mmm Dd Hh:Mm:Ss Z Yyyy"
How to Display a Svg Byte Array as an Image in a Jasperreport
Text-Mouseover Popups Over a Swing Jtextarea
Why Does (360/24)/60 = 0 ... in Java
Adding JPAnels from Other Classes to the Cardlayout
Jtable with Titled Rows and Columns
Detecting Collision of Two Sprites That Can Rotate
12:Xx Shown as 00:Xx in Simpledateformat.Format("Hh:Mm:Ss")
Getting Max Value from an Arraylist of Objects
MAC Osx - Illegalstateexception: the Driver Is Not Executable:
How to Set Icon to a Jlabel from an Image from a Folder
Pass String as Params from One Java App to Another
Cannot Resolve Constructor Firefoxdriver(Org.Openqa.Selenium.Firefox.Firefoxprofile)
Create a Autocompleting Textbox in Java with a Dropdown List