Wish to have some nice time? Check out what I'm reading online!

Java String Concatenation

October 21st, 2009

You have been told many times, don’t use + (java plus operator) to concatenate Strings. We all know that it is not good for performance. Have you researched it? Do you know what is happening behind the hood? Lets explore all about String concatenation now.

In the initial ages of java around jdk 1.2 every body used + to concatenate two String literals. When I say literal I mean it. Strings are immutable. That is, a String cannot be modified. Then what happens when we do

 String fruit = "Apple"; fruit = fruit + "World"; 

In the above java code snippet for String concatenation, it looks like the String is modified. It is not happening. Until JDK 1.4 StringBuffer is used internally and from JDK 1.5 StringBuilder is used to concatenate. After concatenation the resultant StringBuffer or StringBuilder is changed to String.

When java experts say, “don’t use + but use StringBuffer”. If + is going to use StringBuffer internally what big difference it is going to make in String concatenation? Look at the following example. I have used both + and StringBuffer as two different cases. In case 1, I am just using + to concatenate. In case 2, I am changing the String to StringBuffer and then doing the concatenation. Then finally changing it back to String. I used a timer to record the time taken for an example String concatenation.

Look at the output (if you run this java program the result numbers might slightly vary based on your hardware / software configuration). The difference between the two cases is astonishing.

My argument is, if + is using StringBuffer internally for concatenation, then why is this huge difference in time? Let me explain that, when a + is used for concatenation see how many steps are involved:

  1. A StringBuffer object is created
  2. string1 is copied to the newly created StringBuffer object
  3. The “*” is appended to the StringBuffer (concatenation)
  4. The result is converted to back to a String object.
  5. The string1 reference is made to point at that new String.
  6. The old String that string1 previously referenced is then made null.

Hope you understand the serious performance issues and why it is important to use StringBuffer or StringBuilder (from java 1.5) to concatenate Strings.

Therefore you can see initially it was +, then StringBuffer came and now StringBuilder. Surely Java is improving release by release!

Example Java Source Code For String Concatenation

class Clock {

	private final long startTime;

	public Clock() {
		startTime = System.currentTimeMillis();
	}

	public long getElapsedTime() {
		return System.currentTimeMillis() - startTime;
	}
}

public class StringConcatenationExample {

	static final int N = 47500;

	public static void main(String args[]) {

		Clock clock = new Clock();

		//String to be used for concatenation
		String string1 = "";
		for (int i = 1; i <= N; i++) {

			//String concatenation using +
			string1 = string1 + "*";
		}
		//Recording the time taken to concatenate
		System.out.println("Using + Elapsed time: " + clock.getElapsedTime());

		clock = new Clock();
		StringBuffer stringBuffer = new StringBuffer();
		for (int i = 1; i <= N; i++) {

			//String concatenation using StringBuffer
			stringBuffer.append("*");
		}
		String string2 = stringBuffer.toString();
		System.out.println("Using StringBuffer Elapsed time: " + clock.getElapsedTime());

	}
}

Output For The Above Example Program For String Concatenation

Using + Elapsed time: 3687
Using StringBuffer Elapsed time: 16

Hey,
I stumbled upon your website today and I am loving reading your each and every post.
Explanation on java sting manipulation with sample source code is good.
I always wanted to understood JAVA under the hood. And, you are making that very easy for me.
I really appreciate that. :)

Thanks,
Aatish

Aatish on December 3rd, 2009 5:43 am

Hey ur articles are too good…Helping me to understand JAVA better.
Thanks for explaining String concatenation in simple terms. Thanks and keep posting…

Thanks,
Rajitha

Rajitha on December 3rd, 2009 12:45 pm

In doing performance checks, you should never do I/O to
report intermediate logging. Also, you are creating a new
Clock object in-between the code you’re checking – you
can never be sure what the performance penalty is for the
I/O and the object creation (and GC).

The better way to do it is to create some “long” vars before
executing any code that you want to check, such as:

long startTime, middleTime, endTime ;

Then, just before the first line of code to be measured:
[...]
startTime = System.currentTimeMillis();
[...] executable code to be measured

And now, just before the code you want to compare:
[...]
middleTime = System.currentTimeMillis();
[...] executable code that is to be measured /compared

And then finally, get the end time
endTime = System.currentTimeMillis();

Now it’s a simple matter to subtract the values
to arrive at the first section of code and the second
section of code and report the statistics AFTER all
the code has run.

Don’t do I/O and “object creation” during critical
time-checks of code.

mjt on December 17th, 2009 9:37 am

Mjt, I disagree with you on this.

I am measuring performance for only code blocks and not for whole method or program as single unit. When I instantiate the clock object my timer starts and when I print to console, I consider the performance measure as complete. The same steps are repeated again with next code block. I am not measuring to find out performance bottle necks. I am finding out the difference between two code blocks. Time taken for object instantiation and to print will be contributed to both blocks. So the delta will be same in both the measurements.

But the point you mention is good if we are trying to find out performance bottlenecks to optimize the code. But, if you consider popular java profilers, they instrument the byte code to measure performance, which is not a good way of doing it. I agree to that.

Storing time in long variables and at the end subtracting it is a good point. I should have written like that. That’s a nice catch!

Joe on December 17th, 2009 9:47 am

Hey really nice questions and their explanation….good going…m loving reading it…

Ashish on December 25th, 2009 10:22 am

Hey,
Your articles are too good. Helping me to understand JAVA better.Thanks and keep posting….

Thanks,
Saket kumar yadav

saket kumar yadav on January 11th, 2010 7:36 am

it is very good for understanding..thanks to provide the meterial

sivaprasad on March 11th, 2010 3:53 pm

Also worth mentioning that StringBuffer is thread safe, while StringBuilder being more efficient is not thread safe.

Ludic Fallacy on March 29th, 2010 2:18 am

Hi Joseph !

I am really impressed by the way you explain the things.
Short & accurate.
I’ll recommend this website to people to clear their basics
& fill the loop holes.

Great work Man.
Ankur

Ankur on May 24th, 2010 10:50 am

Great work man !!!

Vishal on June 15th, 2010 9:51 am

such amazing information.. its a real treat for all java developers. thanks.

guru on June 15th, 2010 3:23 pm

HI your blog is great undoubtedly. It would br of better help for developers like me if u post a bit more explanations for Threads

Soumik on July 1st, 2010 2:00 pm

Thank you all. @Soumik – I am planning to write on Threads very soon.

Joe on July 1st, 2010 5:59 pm

I think this artice misses the point about using multiple + in a single expression.
For example
String str = “This ” + is +” a dynamic” + string;
Uses a single StringBuilder object behind the scene and is there for is as effective as using it explicitly, e.g.

StringBuilder sb = new StringBuilder();
sb.append(“This “).append(is)
.append(” a dynamic”).append(string);
String str = sb.toString();

Don’t be surprised that because StringBuffer implementation is slower than that of StringBuilder, the expression which uses + is faster than using a StringBuffer explicitly (quite common in pre 1.5 java code).

It’s easy to write a tiny test class to prove it.

Oleg on July 8th, 2010 11:23 am





hidden and gravatar enabled.