Sorry, guys. I’m shocked again. When I was writing code today, I met a yellow prompt in AndroidStudio. I opened it and was surprised.

Let’s start with the code:

Expand the tips to have a look:

`’StringBuilder sb’ can be replaced with ‘String’ less… (Ctrl+F1)

Reports any usages of java.lang.StringBuffer and java.lang.StringBuilder which can be replaced with a single java.lang.String concatenation. Using a String concatenation makes the code shorter and simpler. This inspection only reports when the resulting concatenation is at least as efficient or more efficient than the original StringBuffer or StringBuilder code.`

Note that the StringBuilder or StringBuffer in this code can be replaced with a single String followed by “+”. Using String concatenation makes the code more concise. This code check is only reported if String concatenation is no less efficient than StringBuilder or StringBuffer.

StringBuilder is obviously more efficient, isn’t it? Let’s remember

StringBuilder, StringBuffer, and String.

Immutable Angle difference

  • A String is immutable, and if you try to change its value, a new String is created
  • StringBuffer and StringBuilder are mutable and can change their values.

Thread-safety perspective difference

  • StringBuffer is thread-safe, and when you only need to use strings in a single thread, StringBuilder is a better choice because StringBuilder is more efficient than StringBuffer.

Of course strings are immutable and thread-safe.

  • If you can’t modify strings, of course you should use strings
  • StringBuilder is good enough if your string is going to be modified, for example if there’s some complex logic that’s going to manipulate the string, and it’s only going to be used in a single thread.
  • If your string is going to be modified and you’re going to have multiple threads working on it, then you should use StringBuffer because StringBuffer is thread-safe.

When you try to modify a String, you create a new String, and StringBuilder is a mutable object, so it’s much more efficient.

Is the performance the same?

After some research, the cause was finally found. First we change the code to concatenated form as prompted by the IDE:

    public static void main(String args[]) {

        String s = "AAA";
        String ss = "BBB" + s + "CCC" + 10;

        System.out.println(ss);
    }
Copy the code

Javap -verbose StringBuilderTest ¶

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: ldc           #2                  // String AAA
         2: astore_1
         3: new           #3                  // class java/lang/StringBuilder
         6: dup
         7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        10: ldc           #5                  // String BBB
        12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        15: aload_1
        16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: ldc           #7                  // String CCC
        21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        24: bipush        10
        26: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        29: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        32: astore_2
        33: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
        36: aload_2
        37: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        40: return
Copy the code

Clearly see lines 12, 16, 21, and 26 that the compiler automatically optimizes for us, using the StringBuilder append connection string.

Here we see that even though we use the “+” in the source program, the compiler still converts the “+” into StringBuilder at compile time, which is just as efficient as the AppEnd of StringBuilder in direct code. Studio hints for us because of the simplicity of the code.

Use concatenation in loops

If the concatenation string line expression is simple (the order structure above), then “+” is basically the same as StringBuilder, but if the structure is more complex, such as using loops to concatenate strings, the resulting Java Byte Code will be quite different. Now add a for loop to our code:

public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 0: LDC #2 // String AAA 2: astORE_1 3: LDC #3 // String 5: astore_2 6: iconST_0 7: istore_3 8: ILoAD_3 ** Here begins the loop ** 9: bipush 10 11: if_icmpge 54 14: new #4 // class java/lang/StringBuilder 17: dup 18: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 21: aload_2 22: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 25: ldc #7 // String BBB 27: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 30: aload_1 31: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 34: ldc #8 // String CCC 36: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 39: bipush 10 41: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 44: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 47: astore_2 48: iinc 3, 1 51: Goto 8 jump to loop line 8 do * * * * 54: getstatic # 11 / / Field Java/lang/System. Out: Ljava/IO/PrintStream; 57: aload_2 58: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 61: returnCopy the code

As we can see from the bytecode, the New StringBuilder is inside the loop. So every time we loop, we create a StringBuilder, which is much less efficient than append using a single StringBuilder directly in the code.

So Studio prompts as we would expect.

To summarize: if you are simply concatenating strings in logical order, you can use String “+”, because the compiler will automatically optimize to StringBuilder for you. Studio is aware that since the performance is the same, you need to consider the code readability. If you concatenate strings in a loop, make sure you use the StringBuilder type for much better performance.