1

Given the following two code snippets:

StringBuilder sb = new StringBuilder("");
for (int i = 0; i < 5; i++) {
    sb.append("hello ");
}
System.out.println(sb.toString());

and

String ss = "";
for (int i = 0; i < 5; i++) {
    ss += "hello ";
}
System.out.println(ss);

I read that string concatenation using +, uses StringBuffer or StringBuilder's append method. As far as I know, StringBuilder is mutable, so any modification should not create a new instance. String is immutable, so I expect concatenation in a loop should create a new instance every time (5 times over here). But if + is using StringBuffer or StringBuilder's append method, is it really creating a new instance of ss each time in the loop? Also which among the the code snippets will be more efficient?

Andrej Istomin
  • 2,527
  • 2
  • 15
  • 22
MVKXXX
  • 193
  • 1
  • 2
  • 11
  • `I read that String concatenation using "+", uses StringBuffer or StringBuilder's append method.` Do you have a citation on this? I've never heard this before, and it would definitely disagree with the things I thought I knew about `String` – Silvio Mayolo Dec 11 '22 at 05:39
  • 3
    It was true (as an "implementation detail") for some older versions of Java, but it is no longer true ... and was never specified as being true. – Stephen C Dec 11 '22 at 05:46
  • Concatenation with a single statement may be converted to StringBuilder, but iteratively concatenating in a loop like you're doing has to produce new strings. – shmosel Dec 11 '22 at 05:52
  • Depending on the Java version you're using, you may be interested in [How is String concatenation implemented in Java 9?](https://stackoverflow.com/q/46512888/555045) – harold Dec 11 '22 at 05:52
  • @StephenC Didn't get you there? It was true for some older version but never specified as being true, can you elaborate ? – Ronak Jain Dec 11 '22 at 05:58
  • @RonakJain: What are you asking for details about? It was how the compiler happened to work, but it was never documented and never guaranteed, and now it's changed so the compiler doesn't work that way anymore. – Louis Wasserman Dec 11 '22 at 06:06
  • @RonakJain - How can I give you a citation that something wasn't specified? Look in the specifications where it *would have been* specified, and see what they say. There was (and possibly still is) text in the JLS that mentions that `+` *can be* optimized in various ways, but it doesn't say that it *shall be*. In other words ... it is not normative. – Stephen C Dec 11 '22 at 06:11
  • @StephenC I was just asking about details of what it meant because I didn't understood the statement. Wanted to understand it more. – Ronak Jain Dec 11 '22 at 06:43
  • @RonakJain - Read my answer. – Stephen C Dec 11 '22 at 06:45

3 Answers3

1

It used to be the case that some Java bytecode compilers would compile the String concatenation operator (+) to operations on a temporary StringBuilder.

However:

  • This was an implementation detail. Though the JLS (in some versions1) said that it may be optimized in that way, it was never stated that it shall be.
  • This is not how more recent OpenJDK Java compilers deal with this. Concatenation expressions are now compiled by the bytecode compiler to invokedynamic calls ... which are then optimized by the JIT compiler.

However, your example involves concatenation in a loop. I don't think that JIT compiler in current versions of Java can optimize across multiple loop iterations.

But, that may change too. Indeed, JEP 280 hints that the "indifying" of string concatenations by the bytecode compiler will enable further JIT compiler optimization. That could include optimization of loops like the 2nd version of your example. And if it does change, "hand optimization" to use StringBuilder calls in your source code could actually interfere with the JIT compiler's ability to optimize.

My advice: avoid premature / unnecessary optimization. Unless your application-level profiling tells you that a particular concatenation sequence is a significant bottleneck, leave it alone.


1 - For example, the Java 18 JLS says: "An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression." JLS 15.18.1.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

I'd always use StringBuilder to concatenate strings in a loop. Doing so has several advantages:

  1. you are using StringBuilder what is made to do, so it is easier to read (but less concise);
  2. you can pass StringBuilder around using method arguments (if you'd use the immutable String you can only use it as return value);
  3. StringBuilder has additional options to alter the string if that would be necessary;
  4. it will allocate some buffer space in advance, so that subsequent alterations / concatenations don't take that much memory;
  5. it can be assumed to be relatively performant whichever direction the current JVM takes when it comes to string concatenation.

Of course, I'd use new StringBuilder() instead of the new StringBuilder("") which makes no sense - StringBuilder instances will already start with an empty string (and 16 characters of buffer space).

If you know the size of the string in advance then it does make sense to create a buffer large enough to hold it, so it doesn't need to request a larger area to hold the characters. Memory management is relatively expensive.

With regard to that, note that StringBuilder implements CharSequence so you can actually use it instead of a String for some methods if you want to avoid copies.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
-2

"Concatenate" joins two specific items together, whereas "append " adds what you specify to whatever may already be there