Java String Concatenation

Last modified on September 30th, 2014 by Joe.

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

Comments on "Java String Concatenation"

  1. Aatish says:

    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

  2. Rajitha says:

    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

  3. mjt says:

    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.

  4. Joe says:

    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!

  5. Ashish says:

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

  6. saket kumar yadav says:

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

    Thanks,
    Saket kumar yadav

  7. sivaprasad says:

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

  8. Ludic Fallacy says:

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

  9. Ankur says:

    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

  10. Vishal says:

    Great work man !!!

  11. guru says:

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

  12. Soumik says:

    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

  13. Joe says:

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

  14. Oleg says:

    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.

  15. Anonymous says:

    MJT is right!
    I modified your code with his hints in mind.
    The values I received were 13407 and 9507 respectively!

  16. Anonymous says:

    Your explanation is very good.
    Thanks for these articles…..

  17. Vinayak says:

    Wow! Thanks a ton! I really didn’t knew this.

  18. Tanushree says:

    Hi,
    Can you tell me what precautions should be taken while using toString()?

    I’m really impressed by this site. Thanks for this site.

  19. Sushant says:

    Gud going mate. Really helpful articles.

  20. santosh says:

    realy fruitful…thanks 4 making things simple…

  21. krishna says:

    fabulous dude…!! ur website rocks…!! Keep it Up..!!

  22. Scott Jones says:

    Your comparison test is bogus:

    String string1 = “”;
    for (int i = 1; i <= N; i++) {

    //String concatenation using +
    string1 = string1 + "*";
    }

    …is not the same as:

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

    //String concatenation using StringBuffer
    stringBuffer.append("*");
    }

    These two tests are not equivalent. An equivalent code snippet using StringBuffer is:

    String string1 = "";
    for (int i = 1; i <= N; i++) {
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer.append(string1);
    stringBuffer.append("*");
    string1 = stringBuffer.toString();
    }

    As you can see, a new StringBuffer is instantiated for each iteration. That is causing the slow down.

    But there is absolutely no difference between these two lines as far as the byte code and performance is concerned:

    /*1.*/ String foobar = "hello" + ", " + "world";

    /*2.*/ String foobar = new StringBuilder().append("hello").append(", ").append("world");

    …in fact line 1 is converted to line two under the covers by the compiler before being converted to byte code.

  23. Lazza says:

    Scott, I think you’ve missed the point of the article.

    Your code quite correctly shows how to use StringBuffer explicitly to achieve the same inefficiency as the + operator – but that’s exactly why you don’t want to use either one in this case.

    The example is taking an existing string, and appending to it a number of times. Using a single StringBuffer and .append is much faster than the + operator, OR instantiating a new StringBuffer for each append.

    Single-line efficiency is also another matter, as you point out. That doesn’t change the validity of the article, which is not dealing with several appends.

    You’re correct in everything you’ve said, except you’ve misunderstood the context.

  24. Kaushik Sreeram says:

    Nice article

  25. Kaushik Sreeram says:

    @Scott: The equivalent code that you have mentioned infact takes double the time than actual ‘+’.

    Equivalent code which ‘+’ that executes in background and takes same time is:

    — StringBuffer stringBuffer = new StringBuffer();
    — stringBuffer.append(string1);

    ++ StringBuffer stringBuffer = new StringBuffer(string1);

    The only difference is, to copy original string content, the above code instantiates StringBuffer’s parametarized constructor with string as parameter where

    as your code first instantiates StringBuffer’s default constructor and then calls StringBuffer.append().

    Lets look at implementation of constructors:
    public StringBuffer() {
    super(16);
    }

    public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
    }

    There is advantage with StringBuffer’s parameterized constructor calling StringBuffer.append() over we calling StringBuffer.append()

    The StringBuffer.append() function checks for its capacity, if its not sufficient it does expansion and then appends.
    Expansion includes multiple steps like: creation of new char array, use System.arrayCopy to copy old char array to new one, and then returns newly created array’s reference.

    Where as parameterized constructor accepting string know the length of string, using that it creates exact character capacity for string buffer so that

    append function does not need to expand again as it has sufficient capacity.

    In your code, StringBuffer.append() after exceeding 16 char length calls expands for every iteration when you append ‘*’ which takes even more time.

  26. Sangeeth C says:

    Hai, i love the way explained keep it up
    thanks for this article.

  27. anil says:

    Hi,
    can u send the solution for
    string reverse without using any string functions …

  28. Java String says:

    […] + is a special operator when it comes to java String. It helps to concatenate two String. I have already written a post exclusively for String concatenation. Please refer that for more on java String concatenation. […]

  29. Alaap Sharma says:

    Lovely articles. Thanks a ton Joe. GOD bless U.

    Keep it up.

    Regards
    Alaap Sharma

  30. John Jai says:

    Good Explanations Joe…

    Nandri Nandri ! :)

  31. Anonymous says:

    Very good article, with clear explanation

  32. Harikrishna Chowdary says:

    nice explanation joe…

    how can i create an object to a class which is having private constructor ??
    Can u explain this ?
    Thanks in advance

  33. Anonymous says:

    it helps me a lot

  34. Mayuri wankhade says:

    Hi ,

    What are the methods whic differentiate string from strinBuffer? and also explain every time the new string object is created when using concatenation..

    it is superb article

  35. Anonymous says:

    Really a very nice and simple way to understand basics for String class.

  36. Anonymous says:

    hi!!
    every one knows this.. do you know the difference between concat() and +

  37. Kashinath says:

    Hey Joe,

    Your articles are really helpful . Is there any way i can download all your articles for offline reading.

  38. kakuru says:

    your articles have added me great impact..with clear explanation
    kakuru edward makerere university

  39. Anonymous says:

    gud explain joe,Keep it up

  40. Louftansa says:

    Hi,

    I’m reading you from France, your website is really amazing and very clear. Thank you for sharing your knowledge with us.

  41. prakash says:

    hello sir i had one doubt in string handling
    string s1=”abc”;
    string s2=”123″
    i need the output as a1,b2,c3;
    is this possiable to do the answer….

  42. Gaurav says:

    my doubt is about string concatenation :
    class Test
    {
    char arr[]={‘a’,’b’};
    String s=”asdf”;
    System.out.print(s); // o/p: asdf
    System.out.print(arr); // o/p: ab
    System.out.print(“ok “+s); // o/p: ok asdf
    System.out.print(“ok “+arr);
    // ok c[address
    }
    // if i concatenate any string with any reference (except string reference) then i got address but i expect the string conversion of the object refer by that reference because implicitly tostring() function is call for that reference but in practical i got address type hexadecimal number . why ? please help me out…

  43. Anonymous says:

    Hi Joe,

    I really love the clear, concise and to the point explanation with great examples. All your blogs are based on concepts which are well known and very useful practically. Thanks for sharing your knowledge!

  44. Steven says:

    Hi Joe,

    I really love the way you project any topic. Keep going.

    Thanks a ton.

  45. raksha singh says:

    It was useful… well done :)

  46. Kundan Kumar says:

    Can u explain about the output of below line of code.

    1. String str1 = null;
    2. String str2 = Hello;
    3. SOP(str1.concatenate(str2));
    4. SOP(str1+str2);

    output : line three throw null pointer exception but why line 4. is print nullHello.

  47. Yatheesh says:

    images u kept are very nice and informative

  48. Yatheesh says:

    hi kundan, NullPointerException will come only when we call a method with null object. In ur 4rth case ur not calling any method using null object, instead ur just appending one string with other

  49. raj says:

    Thanks for sharing your knowledge, which is GREAT thing.

  50. Fazila Ashraf says:

    really ausam website..
    thanks for helping :)

  51. rakesh says:

    learning java behind to hood is boosting my confidence on java….so keep on providing these useful tutorials

  52. anjali says:

    excellent

  53. sapan says:

    @Joe this is nice explanation but i still have doubt like from the following code how many object will be created JVM memory.

    String s1=”abc”;
    String S2=new String(“abc”);
    String s3 = s1 + “efg”;
    String s4 = s2 + “efg”;

  54. guna says:

    i need program for this Write the code to find the common alphabets in AMITABH BACHCHAN and RAJNIKANTH using any language sent to my id gunasks@live.com

  55. Hemang Rami says:

    Hey, thanks for providing such information. I was knowing this as I use to do findbug on my code. But your test program total blowed my mind when i test it with N=10 Lakh.

  56. Joe says:

    Wow! thats nice. Thanks.

  57. Anonymous says:

    Every topic you have written about covers not just the “what is..” but the “why” & “how” too and in a very simple & interesting manner.

    Thank you so much for posting articles ..

  58. Java Array says:

    […] is a String but this is not the case in java arrays. But the same behaviour is implemented as a StringBuffer wherein the contents are […]

  59. Ulrik says:

    This article shows a valid point, but it would be more interesting if another point was made clear – that using StringBuilder is even more efficient that StringBuffer, because it is not synchronized. This means that it is not thread-safe, but when using it as a local variable inside a method, that is not an issue.

    When I run the code example with a third variant using StringBuilder, the StringBuilder version is about twice as fast as the StringBuffer version, which in turn is 10-15 times faster than using +.

    Results from my machine:

    Using + Elapsed time: 576
    Using StringBuffer Elapsed time: 4
    Using StringBuilder Elapsed time: 2

  60. Eshwar Chandra V says:

    Really enjoying reading the articles… Very nicely crispy clear while reading the concepts… Really GOOD JOB…. :)

Comments are closed for "Java String Concatenation".