MetallicPriest
MetallicPriest

Reputation: 30755

Is String concatenation on assignment efficient?

I know that using the "+" concatenation operator for building strings is very inefficient, and that is why it is recommended to use the StringBuilder class, but I was wondering if this kind of pattern is inefficient too?

String some = a + "\t" + b + "\t" + c + "\t" + d + "\t" + e;

I guess here the compiler will optimize the assignment fine, or not?

Upvotes: 2

Views: 1161

Answers (3)

Karol Dowbecki
Karol Dowbecki

Reputation: 44942

This particular example will be inlined by the compiler:

String a = "a";
String b = "bb";
String c = "ccc";
String some = a + "\t" + b + "\t" + c;

Java 9+ will inline this using invokedynamic with makeConcatWithConstants making it efficient. As per javap -v output:

Code:
  stack=3, locals=5, args_size=1
     0: ldc           #2                  // String a
     2: astore_1
     3: ldc           #3                  // String bb
     5: astore_2
     6: ldc           #4                  // String ccc
     8: astore_3
     9: aload_1
    10: aload_2
    11: aload_3
    12: invokedynamic #5,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    17: astore        4
    19: return

However if the a b and c are compile time constants compiler will further optimize the code:

final String a = "a";
final String b = "bb";
final String c = "ccc";
String some = a + "\t" + b + "\t" + c;

and some will be loaded with a constant value:

Code:
  stack=1, locals=5, args_size=1
     0: ldc           #2                  // String a
     2: astore_1
     3: ldc           #3                  // String bb
     5: astore_2
     6: ldc           #4                  // String ccc
     8: astore_3
     9: ldc           #5                  // String a\tbb\tccc
    11: astore        4
    13: return

In other circumstances e.g. for loop the compiler might not be able to produce optimized code so StringBuilder might be faster.

Upvotes: 5

Oleg Cherednik
Oleg Cherednik

Reputation: 18245

In general case, string concatenation with + and using StringBuilder is absolute correct and working. But in different situations concatenation with + becomes less efficient, than using StringBuilder.

String concatenation NOT IN LOOP - EFFICIENT!!!

This makes good performance, because JVM transforms this using StringBuilder.

String some = a + "\t" + b + "\t" + c + "\t" + d + "\t" + e;

This is OK, because JVM internally change this code to the following one:

String some = new StringBuilder().append(a).append('\t').append(c).append('\t')
                                 .append(d).append('\t').append(e).toString();

P.S. StringBuilder has internal buffer char[]. In case you know how long will be result string, then it's better to reserve whole buffer in the beginning. E.g. in case of final string will be at most 1024 characters, then you could do new StringBuilder(1024)

String concatenation IN LOOP - NOT EFFICIENT!!!

This makes bad performance, because JVM cannot wrap while loop with one StringBuilder, like this:

StringBuilder buf = new StringBuilder();

for (int i = 0; i < 10; i++)
    buf.append(a).append('\t').append(c).append('\t')
       .append(d).append('\t').append(e).append('t');

String some = buf.toString();

but JVM still able to optimize all concatenations within each loop iterations; like this:

String some = "";

for (int i = 0; i < 10; i++) {
    some = new StringBuilder(some).append(a).append('\t').append(c).append('\t')
                               .append(d).append('\t').append(e).append('t');
}

As you can see, ther're some disadvantages of using string concatenation in loop.

Upvotes: 2

Holger
Holger

Reputation: 298123

Your premise “that using the "+" concatenation operator for building strings is very inefficient”, is not correct. First, string concatenation itself is not a cheap operation, as it implies creating a new string containing all concatenated strings, hence, needing to copy the character contents. But this does always apply, regardless of how you do it.

When you use the + operator, you’re telling what you want to do, without saying how to do it. Not even the Java Language Specification demands a particular implementation strategy, except that the concatenation of compile-time constants must be done at compile time. So for compile-time constants, the + operator is the most efficient solution¹.

In practice, all commonly used compilers from Java 5 to Java 8 generate code using a StringBuilder under the hood (before Java 5, they used StringBuffer). This applies to statements like yours, so replacing it with a manual StringBuilder use would not gain much. You could be slightly better than the typical compiler generated code by providing a reasonable initial capacity, but that’s all.

Starting with Java 9, compilers generate an invokedynamic instruction which allows the runtime to provide the actual code performing the concatenation. This could be a StringBuilder code similar to the one used in the past, but also something entirely different. Most notably, the runtime provided code can access implementation specific features, which the application code could not. So now, the string concatenation via + can be even faster than StringBuilder based code.

Since this applies to a single concatenation expression only, when performing a string construction using multiple statements or even a loop, using a StringBuilder consistently during the entire construction may be faster than the multiple concatenation operations. However, since the code runs in an optimizing environment, with a JVM recognizing some of these patterns, not even that can be said for sure.

This is the time to remember the old rule, to only try to optimize performance, when there is an actual problem with the performance. And always verify with impartial measuring tools, whether an attempted optimization truly improves the performance. There are a lot of widespread myths, wrong or outdated, about performance optimization tricks.

¹ except you have repeated parts and want to reduce the size of the class file

Upvotes: 6

Related Questions