String concatenation: concat() vs “+” operator

2018-12-31 02:39发布

Assuming String a and b:

a += b
a = a.concat(b)

Under the hood, are they the same thing?

Here is concat decompiled as reference. I'd like to be able to decompile the + operator as well to see what that does.

public String concat(String s) {

    int i = s.length();
    if (i == 0) {
        return this;
    }
    else {
        char ac[] = new char[count + i];
        getChars(0, count, ac, 0);
        s.getChars(0, i, ac, count);
        return new String(0, count + i, ac);
    }
}

11条回答
宁负流年不负卿
2楼-- · 2018-12-31 03:08

I don't think so.

a.concat(b) is implemented in String and I think the implementation didn't change much since early java machines. The + operation implementation depends on Java version and compiler. Currently + is implemented using StringBuffer to make the operation as fast as possible. Maybe in the future, this will change. In earlier versions of java + operation on Strings was much slower as it produced intermediate results.

I guess that += is implemented using + and similarly optimized.

查看更多
若你有天会懂
3楼-- · 2018-12-31 03:10

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.

查看更多
何处买醉
4楼-- · 2018-12-31 03:12

Niyaz is correct, but it's also worth noting that the special + operator can be converted into something more efficient by the Java compiler. Java has a StringBuilder class which represents a non-thread-safe, mutable String. When performing a bunch of String concatenations, the Java compiler silently converts

String a = b + c + d;

into

String a = new StringBuilder(b).append(c).append(d).toString();

which for large strings is significantly more efficient. As far as I know, this does not happen when you use the concat method.

However, the concat method is more efficient when concatenating an empty String onto an existing String. In this case, the JVM does not need to create a new String object and can simply return the existing one. See the concat documentation to confirm this.

So if you're super-concerned about efficiency then you should use the concat method when concatenating possibly-empty Strings, and use + otherwise. However, the performance difference should be negligible and you probably shouldn't ever worry about this.

查看更多
柔情千种
5楼-- · 2018-12-31 03:19

Basically, there are two important differences between + and the concat method.

  1. If you are using the concat method then you would only be able to concatenate strings while in case of the + operator, you can also concatenate the string with any data type.

    For Example:

    String s = 10 + "Hello";
    

    In this case, the output should be 10Hello.

    String s = "I";
    String s1 = s.concat("am").concat("good").concat("boy");
    System.out.println(s1);
    

    In the above case you have to provide two strings mandatory.

  2. The second and main difference between + and concat is that:

    Case 1: Suppose I concat the same strings with concat operator in this way

    String s="I";
    String s1=s.concat("am").concat("good").concat("boy");
    System.out.println(s1);
    

    In this case total number of objects created in the pool are 7 like this:

    I
    am
    good
    boy
    Iam
    Iamgood
    Iamgoodboy
    

    Case 2:

    Now I am going to concatinate the same strings via + operator

    String s="I"+"am"+"good"+"boy";
    System.out.println(s);
    

    In the above case total number of objects created are only 5.

    Actually when we concatinate the strings via + operator then it maintains a StringBuffer class to perform the same task as follows:-

    StringBuffer sb = new StringBuffer("I");
    sb.append("am");
    sb.append("good");
    sb.append("boy");
    System.out.println(sb);
    

    In this way it will create only five objects.

So guys these are the basic differences between + and the concat method. Enjoy :)

查看更多
后来的你喜欢了谁
6楼-- · 2018-12-31 03:20

How about some simple testing? Used the code below:

long start = System.currentTimeMillis();

String a = "a";

String b = "b";

for (int i = 0; i < 10000000; i++) { //ten million times
     String c = a.concat(b);
}

long end = System.currentTimeMillis();

System.out.println(end - start);
  • The "a + b" version executed in 2500ms.
  • The a.concat(b) executed in 1200ms.

Tested several times. The concat() version execution took half of the time on average.

This result surprised me because the concat() method always creates a new string (it returns a "new String(result)". It's well known that:

String a = new String("a") // more than 20 times slower than String a = "a"

Why wasn't the compiler capable of optimize the string creation in "a + b" code, knowing the it always resulted in the same string? It could avoid a new string creation. If you don't believe the statement above, test for your self.

查看更多
情到深处是孤独
7楼-- · 2018-12-31 03:22

When using +, the speed decreases as the string's length increases, but when using concat, the speed is more stable, and the best option is using the StringBuilder class which has stable speed in order to do that.

I guess you can understand why. But the totally best way for creating long strings is using StringBuilder() and append(), either speed will be unacceptable.

查看更多
登录 后发表回答