When we think about String Concatenation in Java, what comes to our mind is the + operator, one of the easiest ways to join two String or a String, and a numeric in Java. Since Java doesn't support operator overloading, it's pretty special for String to have behavior. But in truth, it is the worst way of concatenating String in Java. When you concatenate two String using + operator e.g. "" + 101, one of the popular ways to convert int to String, compiler internally translates that to StringBuilder append call, which results in the allocation of temporary objects.
You can see the real difference in the performance of our example program, in which we have concatenated 100,000 String using the + operator. Anyway, this article is not just about + operator but also about other ways to concatenate multiple Strings.
There are four ways to do this, apart from the + operator, we can use StringBuffer, StringBuilder, and concat() method from java.lang.String class for the same purpose.
Both StringBuilder and StringBuffer classes are there for just this reason, and you can see that in our performance comparison. StringBuilder is the winner and the fastest way to concatenate Strings. StringBuffer is a close second, because of the synchronized method, and the rest of them are just 1000 times slower than them.
Both StringBuilder and StringBuffer classes are there for just this reason, and you can see that in our performance comparison. StringBuilder is the winner and the fastest way to concatenate Strings. StringBuffer is a close second, because of the synchronized method, and the rest of them are just 1000 times slower than them.
4 ways to concatenate String in Java
Here we will see examples of all four ways of concatenating Strings in Java. Starting with the most popular approach, joining string using + operator.
1. String Concatenation using + Operator
The easiest way of joining multiple String and numeric values in Java. Just remember that, when you have two or more primitive type values e.g. char, short, or int, at the beginning of your string concatenation, you need to explicitly convert the first of them to a String.For example System.out.println(200 + 'B' + ""); will not print 200B, instead, it will print 266, by taking ASCII values of 'B' and adding them to 200.
On the other hand System.out.println("" + 200 + 'B') will print 200B. Unfortunately, this is the worst way to concatenate String in Java. Let's take a look at how the String concatenation operator works in Java. When we write :
it's translated into
All + operator are translated into several StringBuilder.append() calls before final toString() call.
Since StringBuilder(String) constructor allocates a buffer with only 16 char, appending more than 16 characters will require buffer reallocation. At last, StringBuffer.toString() calls create a new String object with a copy of the StringBuilder buffer.
This means, to concatenate two String, you will need to allocate, one StringBuilder, one char array[16], one String object and another char[] of appropriate size to fit your input value. Imagine if you are doing these thousands of times in your application, it's not only slow but also increases the workload of Garbage Collector.
You can also see Java Performance The Definitive Guide By Scott Oaks to learn more about how to do performance testing in Java and how to tune different things in the Java ecosystem to get the best performance from your Java application.
The performance of concat() method is similar to the + operator and I don't recommend using it for any production purpose.
On the other hand System.out.println("" + 200 + 'B') will print 200B. Unfortunately, this is the worst way to concatenate String in Java. Let's take a look at how the String concatenation operator works in Java. When we write :
String temp = "" + 200 + 'B';
it's translated into
new StringBuilder().append( "" ).append( 200 ).append('B').toString();
All + operator are translated into several StringBuilder.append() calls before final toString() call.
Since StringBuilder(String) constructor allocates a buffer with only 16 char, appending more than 16 characters will require buffer reallocation. At last, StringBuffer.toString() calls create a new String object with a copy of the StringBuilder buffer.
This means, to concatenate two String, you will need to allocate, one StringBuilder, one char array[16], one String object and another char[] of appropriate size to fit your input value. Imagine if you are doing these thousands of times in your application, it's not only slow but also increases the workload of Garbage Collector.
You can also see Java Performance The Definitive Guide By Scott Oaks to learn more about how to do performance testing in Java and how to tune different things in the Java ecosystem to get the best performance from your Java application.
2. Using concat() method from java.lang.String
Concat(String str) method concatenates the specified String to the end of this string. I have hardly seen this used for concatenation, though. Inside, it allocates a char[] of length equal to the combined length of two String, copies String data into it, and creates a new String object using private String constructor, which doesn't make a copy of input char[], as shown below.public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); } /* * Package private constructor which shares value array for speed. * this constructor is always expected to be called with share==true. * a separate constructor is needed because we already have a public * String(char[]) constructor that makes a copy of the given char[]. */ String(char[] value, boolean share) { // assert share : "unshared not supported"; this.value = value; }
The performance of concat() method is similar to the + operator and I don't recommend using it for any production purpose.
3. Using StringBuffer
This was the proper way to concatenate multiple String, integer, and others prior to Java 5 when StringBuilder was not available. It's much faster than the + operator and concert() method. The only drawback of this class is that all its append methods are synchronized.Since we hardly share temporary string in a concurrent environment, the price for thread-safety is not desired in many cases, that's where StringBuilder is used.
It works similarly to StringBuilder synchronization. It also provides several overloaded append() methods to concatenate integer, char, short, etc.
4. Using StringBuilder
This is the best way to concatenate String in Java, especially when you are concatenating multiple Strings. It's not thread-safe, but you hardly need that during String concatenation. In the next section, we will see a performance comparison of all these 4 ways to concatenate String in Java.From JDK 8 onwards, you can also use StringJoiner to concatenate in Java. I am not including StringJoiner in this article but you can also these 10 examples of StringJoiner to learn more about it.
Performance comparison + Operator vs Concat vs StringBuffer vs StringBuilder
here is a sample Java program to find out which method gives us best performance for String concatenation.public class Demo{ public static void main(String args[]) throws IOException { final int ITERATION = 100_000; String s = ""; // String Concatenation using + operator long startTime = System.nanoTime(); for (int i = 0; i < ITERATION; i++) { s = s + Integer.toString(i); } long duration = (System.nanoTime() - startTime) / 1000; System.out.println("Time taken to concatenate 100000 Strings using + operator (in micro) : " + duration); // Using String concat() method startTime = System.nanoTime(); for (int i = 0; i < ITERATION; i++) { s.concat(Integer.toString(i)); } duration = (System.nanoTime() - startTime) / 1000; System.out.println("Time taken to concatenate 100000 Strings using concat method (in micro) : " + duration); // StringBuffer example to concate String in Java StringBuffer buffer = new StringBuffer(); // default size 16 startTime = System.nanoTime(); for (int i = 0; i < ITERATION; i++) { buffer.append(i); } duration = (System.nanoTime() - startTime) / 1000; System.out.println("Time taken to concatenate 100000 Strings using StringBuffer (in micro) : " + duration); // StringBuilder example to concate two String in Java StringBuilder builder = new StringBuilder(); //default size for worst case startTime = System.nanoTime(); for (int i = 0; i < ITERATION; i++) { builder.append(i); } duration = (System.nanoTime() - startTime) / 1000; System.out.println("Time taken to concatenate 100000 Strings using StringBuilder append in micro) : " + duration); } } Output: Time taken to concatenate 100000 Strings using + operator (in micro) : 29178349 Time taken to concatenate 100000 Strings using concat method (in micro) : 21319431 Time taken to concatenate 100000 Strings using StringBuffer (in micro) : 12557 Time taken to concatenate 100000 Strings using StringBuilder append (in micro) : 10641
You can clearly see that given everything the same, StringBuilder outperforms all others. It's almost 3000 times faster than + operator. concat() method is better than + operator but still very bad compared to StringBuffer and StringBuilder.
StringBuffer took more time than StringBuilder because of synchronized method. I know that, you hardly join 100K Strings but even for small numbers it adds. if you run program to join just 10 Strings, you will notice significant difference in time spent Here is what I got when I ran this program for 10 iteration only :
Though using the + operator along with empty String is easiest and obvious way to concatenate multiple String and numeric in Java, you should not use that, especially inside loops. Always use StringBuilder for string concatenation, the class is there for a reason, and if you are still using StringBuffer then get rid of that, because most of the time you don't really need the thread-safety overhead of StringBuffer.
+ operator took (in micros) : 177 concat() method took (in micros) : 28 StringBuffer took (in micros) : 21 StringBuilder append took (in micros) : 8
Though using the + operator along with empty String is easiest and obvious way to concatenate multiple String and numeric in Java, you should not use that, especially inside loops. Always use StringBuilder for string concatenation, the class is there for a reason, and if you are still using StringBuffer then get rid of that, because most of the time you don't really need the thread-safety overhead of StringBuffer.
Unfortunately, concat() method is only good when you need to concatenate exactly 2 strings. In short, always use StringBuilder to concatenate Strings in Java.
If you like this tutorial and want to learn more about String class in Java, check out these amazing String tutorials from Java67 blog :
If you like this tutorial and want to learn more about String class in Java, check out these amazing String tutorials from Java67 blog :
- How to convert Enumeration type to String in Java
- How to check if a String contains one number in Java
- ArrayList to String in Java
- Difference between StringBuilder and StringBuffer in Java
- How to find if String is Empty in Java
- How to convert array to String in Java
- How to reverse String in Java
- Difference between String object and literal in Java
- Difference between String and StringBuffer in Java
- Best way to compare two Strings in Java
- How to remove whitespace form String in Java
Over to you, what is your favorite way to concatenate String in Java? Plus operator, StirngBuffer, StringBuilder, StringJoiner or anything else?
From Java >1.6 plus operator is changed into StringBuilder by compiler. So what is the point in making code less readable by StringBuilder?
ReplyDelete@Michal, there are cases where using + operator is not optimal e.g. concatenating in loop, because Java will internally create and destroy StringBuilder instances. Sometime its better to have one StringBuilder object outside loop and just append on it while iterating over loop, instead of using + operator.
DeleteYes there are cases, but these will make about 0.000000000001% of cases; making the explicit use of stringbuilder just a waste of time (and an unneeded premature optimization)
DeleteIt depends on one's preferences and/or string you are creating but using StringBuilder might be far more readable than + operator.
DeleteI ran your code and got similar results. However, when I added a couple more cases, I was surprised:
ReplyDeleteCase 1 - building a new string using '+'. (s = "one" + 2 + 3.0;)
Case 2 - build a new string using StringBuilder (s = new StringBuilder().append("one").append(2).append(3.0).toString();)
These results were MUCH different from your examples of *appending* to an existing string. In fact, using the '+' method was 100 times faster!
Hi, I added the String.join method like this:
ReplyDeletestartTime = System.nanoTime();
for (int i = 0; i < ITERATION; i++) {
s = String.join(" ", Integer.toString(i));
}
duration = (System.nanoTime() - startTime) / 1000;
System.out
.println("Time taken to concatenate 100000 Strings using String.join in micro) : " + duration);
it was much faster than concat and closer to the StringBuilder
final int ITERATION = 100_0;
ReplyDeleteits giving strange result. Making StringBuffer fastest ?
Time taken to concatenate 100000 Strings using + operator (in micro) : 9053
Time taken to concatenate 100000 Strings using concat method (in micro) : 3796
Time taken to concatenate 100000 Strings using StringBuffer (in micro) : 469
Time taken to concatenate 100000 Strings using StringBuilder append in micro) : 485
Hello Shashank, which version of JDK you are using? StringBuffer is not really a problem in single threaded environment because uncontented lock acquisition has become faster with latest JVM and JIT version.
ReplyDeleteAny analysis on String.format?
ReplyDeleteA few corrections to make the test fair.
ReplyDelete1. Both StringBuilder and StringBuffer need to produce their merged string result by calling toString() inside the timing fence.
2. The concat call also needs to save its result as in:
s = s.concat(i);
3. The working String s needs to be reset prior to each test that uses it.
s = "";
4. Appending an integer to a String is not a good test of the string functions. It is possible a bulk of the time measured will be the conversion of the integer to a string. This conversion is constant on all the tests. I would recommend appending a constant String value rather then a converted integer.
5. I find StringBuilder surprisingly inefficient with its memory management. It is filling a regrowing array of character array rather then a single pass merging all of the results. If you want to reduce your memory hit and your source strings are persistent (not coming from a file or stream), you may want an alternate solution like:
http://landenlabs.com/android/weakness/java-weakness.html#java.stringbuilder
Lastly - I find all good benchmarks should verify the functions are producing identical results. The testing should include the display of a hash code of the function results.
how to concat
ReplyDelete(what)
and (is java?)
so that the output will be as ( what is java )...
In method 2, what is variable value refers to ?
ReplyDeleteHello giri, it refers to instance variable value in the String class. See the full code from java.lang.String class in Eclipse.
Delete