String vs StringBuffer

Before we discuss the differences between String and StringBuffer in Java, lets first talk a little bit about Strings. Strings are immutable and read-only. In other words, Strings can’t be changed.

Ok, you’re thinking. So, Strings are immutable. But what implications does that actually have and why should I care?

Well, an example always helps! Let’s say that we have a string like this:

String test = “xyz”;

Now, what if we want to add something to the string? In other words, what if we want to concatenate something to the end of the string? Like this:

test = test + “abc”;  //test is now "xyzabc"

Because Strings are immutable in Java, we technically can not change the internal state of the String – we can’t change the “xyz”. Note the emphasis on “internal” state. So, and this is the key point to understand here, Java will actually create an entirely new String in memory, which will store the result of that concatenation – “xyzabc”.

Let’s repeat this in other words so that you really understand this point. You can imagine the string “xyz” as occupying some place in memory. The internal state of the String variable test – which is “xyz” – can not be changed (Strings are immutable!) so when Java sees that we want to modify the internal state of the test variable, it instead just creates a new, separate space in memory that stores the result of the concatenation – “xyzabc”.

So, the main problem here is that extra memory is being used to create a new String object because String is immutable.

If String were mutable we could just go to the place in memory where “xyz” is stored and simply change the “internal” state to “xyzabc” – which would of course save memory.

That being said, a lot of the newer Java compilers will actually optimize the code by taking that String code and changing it to use StringBuilder – which is mutable. The fact that it’s mutable is the key here.

So this code:

String test = "xyz";
test = test + “abc”;  //test is now "xyzabc"

Could be changed to this code by some newer compilers:

StringBuilder sb = new StringBuilder("xyz");
sb.append("abc");//append is just like a concatenation

The reason using StringBuilder is more efficient is because it’s mutable, and that means it can go ahead and modify the internal character array unlike String. And, that means it does NOT have to create a new String object. So, with StringBuilder, it just goes to wherever “xyz” is stored and just changes “xyz” to “xyzabc” instead of creating a new place in memory for “xyzabc”.

What about StringBuffer?

StringBuffer is the same thing as StringBuilder in all respects except one – StringBuffer is synchronized, but StringBuilder is not synchronized. Being synchronized adds overhead to StringBuffer, which is why StringBuilder is actually preferred now.

Using String in a loop

Note that in the example we gave above we only really showed just one simple concatenation of a String. But the time when using Strings can really cause a hit on your performance is when you are doing String concatenation in a loop, like this:

String str = new String(); 
for (int k = 0; k < 500; k++) { 
str = str + k; //concatenate value of k to the string 
}

The problem with the code above is that for each and every iteration in that loop a new String object will have to be allocated - 500 times. Again, this is because Strings are immutable. This can be a big performance hit. So, it's much better to change this to use a StringBuilder instead for reasons we already explained above. Also note that the compiler will not make this optimization for you so you must do it yourself:

StringBuilder sb = new StringBuilder();
for (int k = 0; k < 500; k++) {
    sb.append(k);
}

The code above will be far more efficient than using String, because StringBuilder is mutable.





Follow Varoon Sahgal, author, on Google Plus