String Concatenation: Concat() VS "+" Operator

String concatenation: concat() vs + operator

No, not quite.

Firstly, there's a slight difference in semantics. If a is null, then a.concat(b) throws a NullPointerException but a+=b will treat the original value of a as if it were null. Furthermore, the concat() method only accepts String values while the + operator will silently convert the argument to a String (using the toString() method for objects). So the concat() method is more strict in what it accepts.

To look under the hood, write a simple class with a += b;

public class Concat {
String cat(String a, String b) {
a += b;
return a;
}
}

Now disassemble with javap -c (included in the Sun JDK). You should see a listing including:

java.lang.String cat(java.lang.String, java.lang.String);
Code:
0: new #2; //class java/lang/StringBuilder
3: dup
4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
7: aload_1
8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
12: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/ String;
18: astore_1
19: aload_1
20: areturn

So, a += b is the equivalent of

a = new StringBuilder()
.append(a)
.append(b)
.toString();

The concat method should be faster. However, with more strings the StringBuilder method wins, at least in terms of performance.

The source code of String and StringBuilder (and its package-private base class) is available in src.zip of the Sun JDK. You can see that you are building up a char array (resizing as necessary) and then throwing it away when you create the final String. In practice memory allocation is surprisingly fast.

Update: As Pawel Adamski notes, performance has changed in more recent HotSpot. javac still produces exactly the same code, but the bytecode compiler cheats. Simple testing entirely fails because the entire body of code is thrown away. Summing System.identityHashCode (not String.hashCode) shows the StringBuffer code has a slight advantage. Subject to change when the next update is released, or if you use a different JVM. From @lukaseder, a list of HotSpot JVM intrinsics.

Concatenation operator (+) vs. concat()

The concat method always produces a new String with the result of concatenation.

The plus operator is backed by StringBuilder creation, appending all String values you need and further toString() calling on it.

So, if you need to concatenate two values, concat() will be better choice. If you need to concatenate 100 values, you should use the plus operator or explicitly use StringBuilder (e.g. in case of appending in a cycle).

Difference between string.concat and the + operator in string concatenation

str.concat(" game"); has the same meaning as str + " game";. If you don't assign the result back somewhere, it's lost. You need to do:

str = str.concat(" game");

What is the difference of + operator and concat() method in JavaScript

There are pretty the same but + is more clear and for sure faster.

Look at this performance test and also see this

It is strongly recommended that assignment operators (+, +=) are used instead of the concat() method.

Difference between string.concat() and + operator

Not in this example.

If you concatenate several strings with + (e.g., "Hello " + user + "!"), current compilers will use a StringBuilder to implement the + operator because this is faster than first creating the string for "Hello " + user and then creating the final string. They probably don't do that for concat(), so there would be a technical difference here.

Edit: see also String concatenation: concat() vs "+" operator and Is there a difference between String concat and the + operator in Java?.

StringBuilder vs. .concat vs. + Operator relative performance different in eclipse than command line?

On Oracle JDK 1.7 (javac 1.7.0_17), the "+" operator is still implemented using StringBuilder, as shown by running javap -c on the class to get the bytecode (only showing the loops here):

public static void plusOperator();
Code:

16: iload 4
18: ldc #10 // int 100000000
20: if_icmpge 53
23: new #11 // class java/lang/StringBuilder
26: dup
27: invokespecial #12 // Method java/lang/StringBuilder."<init>":()V
30: aload_0
31: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: aload_1
35: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
38: aload_2
39: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
42: invokevirtual #14 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
45: astore 5
47: iinc 4, 1
50: goto 16


public static void stringBuilder();
Code:

16: iload 4
18: ldc #10 // int 100000000
20: if_icmpge 50
23: new #11 // class java/lang/StringBuilder
26: dup
27: invokespecial #12 // Method java/lang/StringBuilder."<init>":()V
30: aload_0
31: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: aload_1
35: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
38: aload_2
39: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
42: astore 5
44: iinc 4, 1
47: goto 16

The only difference between these two is that the version with "+" converts the StringBuilder to a String within the loop.

So the question becomes: why does your test show such different results for the same code. Or more completely, why is this not a valid micro-benchmark. Here are some possible reasons:

  • You're counting wall-clock time. This means that you're actually measuring everything that the JVM is doing while running your test. Which includes garbage collection (which is important because you're creating a lot of garbage). You can mitigate this by getting the thread CPU time.
  • You don't verify when or if HotSpot is compiling the methods. This is why you should do a warmup phase before any micro-benchmarks: basically, run your main() multiple times, before you run your actual test.

When to use String#concat() method in Java?

String#concat and + exist to provide a minimalistic set of operations on the type String.

They are not efficient if used multiple times.

But they have their own right as type operations "xxx" + "yyy" you do not want to specify using a StringBuilder. (Furthermore there it is a compile time concatenation.)

StringBuffer is a mistake IMHO. It is slower that the newer StringBuilder as it is synchronized, but one would rarely add something rom two threads (unordered).

String::concat may be a method reference useful for stream reduction or such.

String Concatenation using concat operator (+) or String.format() method

The first won't actually create any extra strings. It will be compiled into something like:

String str = new StringBuilder("This the String1 ")
.append(str1)
.append(" merged with Sting2 ")
.append(str2)
.toString();

Given that the second form requires parsing of the format string, I wouldn't be surprised if the first one actually runs quicker.

However, unless you've got benchmarks to prove that this is really a bit of code which is running too slowly for you, you shouldn't be too worried about the efficiency. You should be more worried about readability. Which code do you find more readable?



Related Topics



Leave a reply



Submit