1

I am dealing with an application that contains lots of legacy code. What I see very often is string concatenation using "+" within a StringBuilder argument.
Example:

StringBuilder sb = new StringBuilder("This " + "looks " + "rather " + "weird " + "to " + "me.") 

From what I've learned the compiler replaces a string concatenation that uses the + operator with StringBuilder().append().
I am afraid now the compiler will create a temporary StringBuilder to perform the concatenation then convert toString() and insert the result into the existing StringBuilder.

My Question is: Is the compiler able to optimize the nested StringBuilder away? And if not should I rewrite the code to save a few CPU cycles? It is obviously working but it hurts my eyes whenever I look at it.

Thanks for any insights!

4
  • Where do you saw compiler replaces a string concatenation that uses the + operator with StringBuilder().append() ? If that was true, we wouldn't care to use StringBuilder or string concatenation Commented Apr 9, 2021 at 10:06
  • @azro: That logic doesn't follow at all. StringBuilder allows you to dynamically append (e.g. in a loop). I believe + does use a StringBuilder. Commented Apr 9, 2021 at 10:06
  • @azro Yes, using concatenation through + will be implicitly translated to use StringBuilder. Only when concatenating over multiple statements, especially when looping, you should use StringBuilder explicitly. Commented Apr 9, 2021 at 10:10
  • @azro: It can be seen in the call stack Commented Apr 9, 2021 at 10:16

2 Answers 2

5

The compiler optimizes concatenation of String literal constants:

StringBuilder sb = new StringBuilder("This " + "looks " + "rather " + "weird " + "to " + "me."); 

is exactly equivalent, at runtime, to:

StringBuilder sb = new StringBuilder("This looks rather weird to me."); 

This also applies to any String compile-time constants, not just literals.

The concern you may have read about is when using non-constants:

StringBuilder sb = new StringBuilder("This " + arg1 + var2); 

is equivalent to:

StringBuilder sb = new StringBuilder(new StringBuilder("This ") .append(arg1) .append(var2) .toString()); 

and it would give you better performance if you re-wrote that as:

StringBuilder sb = new StringBuilder("This ") .append(arg1) .append(var2); 
Sign up to request clarification or add additional context in comments.

1 Comment

If the string builder is not used for anything else, replacing it with "This " + arg1 + var2 is even more efficient. Dealing with a StringBuilder only pays off when conditional fragments or loops are involved. By the way, the compile-time constant folding applies to all constants, not only strings, e.g. "a " + 1 + " b" get compiled to "a 1 b".
1

To add to @k314159's answer, determining how the compiler transforms any particular block of code is easy if you isolate it, compile it with javac, and run the disassembler on it using javap to view the generated (annotated) bytecode.

For example, if you isolate the StringBuilder code into a minimal class:

public class Test { public static void main(String[] args) { StringBuilder sb = new StringBuilder("This " + "looks " + "rather " + "weird " + "to " + "me."); } } 

You can then compile and disassemble the output like so:

javac Test.java && javap -c Test.class 

The output for which is:

Compiled from "Test.java" public class Test { public Test(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/StringBuilder 3: dup 4: ldc #3 // String This looks rather weird to me. 6: invokespecial #4 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 9: astore_1 10: return } 

The line of interest to you, in this case, would be here:

4: ldc #3 // String This looks rather weird to me. 

As you might've guessed, this instruction pushes a (string) constant onto the stack. The annotation clearly states that the constant in this case is a single string, namely: "This looks rather weird to me."

Hopefully that demystifies the internals slightly!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.