Please tell me a real time situation to compare String
, StringBuffer
, and StringBuilder
?
The Basics:
String
is an immutable class, it can't be changed.
StringBuilder is a mutable class that can be appended to, characters replaced or removed and ultimately converted to a String
StringBuffer
is the original synchronized version of StringBuilder
You should prefer StringBuilder
in all cases where you have only a single thread accessing your object.
The Details:
Also note that StringBuilder/Buffers
aren't magic, they just use an Array as a backing object and that Array has to be re-allocated when ever it gets full. Be sure and create your StringBuilder/Buffer
objects large enough originally where they don't have to be constantly re-sized every time .append()
gets called.
The re-sizing can get very degenerate. It basically re-sizes the backing Array to 2 times its current size every time it needs to be expanded. This can result in large amounts of RAM getting allocated and not used when StringBuilder/Buffer
classes start to grow large.
In Java String x = "A" + "B";
uses a StringBuilder
behind the scenes. So for simple cases there is no benefit of declaring your own. But if you are building String
objects that are large, say less than 4k, then declaring StringBuilder sb = StringBuilder(4096);
is much more efficient than concatenation or using the default constructor which is only 16 characters. If your String
is going to be less than 10k then initialize it with the constructor to 10k to be safe. But if it is initialize to 10k then you write 1 character more than 10k, it will get re-allocated and copied to a 20k array. So initializing high is better than to low.
In the auto re-size case, at the 17th character the backing Array gets re-allocated and copied to 32 characters, at the 33th character this happens again and you get to re-allocated and copy the Array into 64 characters. You can see how this degenerates to lots of re-allocations and copies which is what you really are trying to avoid using StringBuilder/Buffer
in the first place.
This is from the JDK 6 Source code for AbstractStringBuilder
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
A best practice is to initialize the StringBuilder/Buffer
a little bit larger than you think you are going to need if you don't know right off hand how big the String
will be but you can guess. One allocation of slightly more memory than you need is going to be better than lots of re-allocations and copies.
Also beware of initializing a StringBuilder/Buffer
with a String
as that will only allocated the size of the String + 16 characters, which in most cases will just start the degenerate re-allocation and copy cycle that you are trying to avoid. The following is straight from the Java 6 source code.
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
If you by chance do end up with an instance of StringBuilder/Buffer
that you didn't create and can't control the constructor that is called, there is a way to avoid the degenerate re-allocate and copy behavior. Call .ensureCapacity() with the size you want to ensure your resulting String
will fit into.
The Alternatives:
Just as a note, if you are doing really heavy String
building and manipulation, there is a much more performance oriented alternative called Ropes.
Another alternative, is to create a StringList
implemenation by sub-classing ArrayList<String>
, and adding counters to track the number of characters on every .append()
and other mutation operations of the list, then override .toString()
to create a StringBuilder
of the exact size you need and loop through the list and build the output, you can even make that StringBuilder
an instance variable and 'cache' the results of .toString()
and only have to re-generate it when something changes.
Also don't forget about String.format()
when building fixed formatted output, which can be optimized by the compiler as they make it better.
Personally, I don't think there is any real world use for StringBuffer
. When would I ever want to communicate between multiple threads by manipulating a character sequence? That doesn't sound useful at all, but maybe I have yet to see the light :)
Mutability Difference:
String
is immutable, if you try to alter their values, another object gets created, whereas StringBuffer
and StringBuilder
are mutable so they can change their values.
Thread-Safety Difference:
The difference between StringBuffer
and StringBuilder
is that StringBuffer
is thread-safe. So when the application needs to be run only in a single thread then it is better to use StringBuilder
. StringBuilder
is more efficient than StringBuffer
.
Situations:
String
object is immutable.StringBuilder
is good enough.StringBuffer
because StringBuffer
is synchronous so you have thread-safety.---------------------------------------------------------------------------------- String StringBuffer StringBuilder ---------------------------------------------------------------------------------- Storage Area | Constant String Pool Heap Heap Modifiable | No (immutable) Yes( mutable ) Yes( mutable ) Thread Safe | Yes Yes No Performance | Fast Very slow Fast ----------------------------------------------------------------------------------
Difference between String and the other two classes is that String is immutable and the other two are mutable classes.
But why we have two classes for same purpose?
Reason is that StringBuffer
is Thread safe and StringBuilder
is not.
StringBuilder
is a new class on StringBuffer Api
and it was introduced in JDK5
and is always recommended if you are working in a Single threaded environment as it is much Faster
For complete Details you can read http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
In java, String is immutable. Being immutable we mean that once a String is created, we can not change its value. StringBuffer is mutable. Once a StringBuffer object is created, we just append the content to the value of object instead of creating a new object. StringBuilder is similar to StringBuffer but it is not thread-safe. Methods of StingBuilder are not synchronized but in comparison to other Strings, the Stringbuilder runs fastest. You can learn difference between String, StringBuilder and StringBuffer by implementing them.