Concatenation operator (+) vs. concat() [duplicate

2019-01-14 15:24发布

问题:

This question already has an answer here:

  • String concatenation: concat() vs “+” operator 11 answers

For string concatenation we can use either the concat() or concat operator (+).

I have tried the following performance test and found concat() is faster and a memory efficient way for string concatenation.

String concatenation comparison for 100,000 times:

String str = null;

//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();

for(int i=0; i<100000; i++){
    str = "Hi";
    str = str+" Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();

long timetaken1 = time2-time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator  :" + "Time taken =" + timetaken1 +
                   " Memory Consumed =" + memoryTaken1);

//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for(int j=0; j<100000; j++){
    str = "Hi";
    str = str.concat(" Bye");
}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();
long timetaken2 = time4-time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method  :" + "Time taken =" + timetaken2 +
                   " Memory Consumed =" + memoryTaken2);

Result

Concat operator: Time taken = 31; Memory Consumed = 2259096
Concat method  : Time taken = 16; Memory Consumed = 299592

If concat() is faster than the operator then when should we use concatenation operator (+)?

回答1:

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).



回答2:

In fact s1 + s2 and s1.concat(s2) are very different.

s1 + s2 is converted by javac into

(new StringBuilder(String.valueOf(s1)).append(s2).toString();

You can see it if you decompile .class. This construct is not very efficient; it involves up to three new char[] allocations and three char[] copy operations.

s1.concat(s2) is always one new char[] + one copy operation, see String.java

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    char buf[] = new char[count + otherLen];
    getChars(0, count, buf, 0);
    str.getChars(0, otherLen, buf, count);
    return new String(0, count + otherLen, buf);
}

Note that new String(int, int, char[]) is String's package private constructor. It uses char buf[] directly, without the usual copying to ensure the buf invisibility for the String immutability.



回答3:

Your test needs to be running for at least 2 seconds with each loop in a separate method to be meaningful. Short tests can be every difficult to reproduce and compare. From your timing it appears you are using Windows (i.e. because you times are 16 and 31 ms ;) Try System.nanoTime() instead. When your loop iterates over 10,000 times the whole method is compiled. This means your later method is already compiled when it is started.

In answer to your question concat is marginally faster when adding two Strings. However, it comes with a typing and conceptual overhead which is likely to be much greater than the CPU you save. Even based on your tests repeating 100,000 times it saves less than 15 ms, and yet it cost you far, far more than that in your time (which is likely to be worth more) You could find in a future version of the JVM, the difference is optimised always and the complexity of your code is still there.


EDIT: I didn't notice that the memory result was suspect.

String str = null;

//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();
for (int i = 0; i < 10000; i++) {
    str = "Hi";
    str = str + " Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();

long timetaken1 = time2 - time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator  :" + "Time taken =" + timetaken1 + " Memory Consumed= " + memoryTaken1);

str = null;
//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for (int j = 0; j < 10000; j++) {
    str = "Hi";
    str = str.concat(" Bye");

}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();

long timetaken2 = time4 - time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method  :" + "Time taken =" + timetaken2 + " Memory Consumed= " + memoryTaken2);

prints when run with -XX:-UseTLAB -mx1g

Concat operator  :Time taken =12 Memory Consumed= 1291456
Concat method  :Time taken =7 Memory Consumed= 560000

making the ratio of memory usage about 2:1. In the original question the result vary every time you run it, sometimes the .concat() appears to use more.



回答4:

I believe the 'style' of concatenation is going to make a difference.

For concat(), it internally creates a new char array buffer, and returns a new string based on that char array.

For the + operator, the compiler in fact translate it to use StringBuffer/StringBuilder.

Therefore, if you are concatenating two strings, concat() is definitely a better choice because the number of objects created is only the result String (and the char buffer used inside), while using the + operator will be translated to:

result = strA + strB;
-- translate to -->
result = new StringBuilder(strA).append(strB).toString();

An extra StringBuilder instance is created.

However, if you are concatenating, for example five strings in a row, each concat() will create a new String object. While using the + operator, the compiler will translate the statement to one StringBuilder with multiple append operations. It is definitely saving a lot of unnecessary temporary object instance:

result = strA + strB + strC + strD + strE;
-- translate to -->
result = new StringBuilder(strA).append(strB).append(strC).append(strD).append(strE).toString();


回答5:

You can always use + if only you use >= Java 1.5 and you don't declare your base String (that you want concatenate) outside of the loop. In Java 1.5 it results in creating new StringBuilder and working on it till your string is complete. That's the fastest way.

Anyway - if you are in a loop (and concatenating strings with +) - every iteration of the loop creates a new StringBuilder - that's not the best idea. So this is where you should force the use of StringBuilder or StringBuffer (thread safe) classes.

Generally, this link clearly answers your question, and gives you complete knowledge:

http://littletutorials.com/2008/07/16/stringbuffer-vs-stringbuilder-performance-comparison/



回答6:

Though both the operator and the method are giving the same output, the way they work internally differs.

The concat() method that just concatenates str1 with str2 and outputs a string, is more efficient for a small number of concatenations.

But with concatenation operator '+', str1+=str2; will be interpreted as str1 = new StringBuilder().append(str1).append(str2).toString();

You can use the concat method when using a fewer number of strings to concatenate. But the StringBuilder method would be fast in terms of performance, if you are using a large number of strings.



回答7:

In general it is a bad practice to concatenate Strings with + and with concat(). If you want to create a String use StringBuilder instead.



回答8:

Actually, both are the same. If you see the code of concat(String paramString) it will return a new object of string, and in the (+) operator it it will also generate a new string object.

If you don't want to create a new object then use string builder to concatenate two strings.