It's bytecode time!
class EmptyString {
public static void main(String[] args) {
String s = "any old string";
s += "";
}
}
javap -c EmptyString
:
Compiled from "EmptyString.java"
class EmptyString extends java.lang.Object{
EmptyString();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String any old string
2: astore_1
3: new #3; //class java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method java/lang/StringBuilder."":()V
10: aload_1
11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6; //String
16: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_1
23: return
}
You can see that +=
causes a StringBuilder
to be created regardless of what it's concatenating, so it can't be optimized at runtime.
On the other hand, if you put both String literals in the same expression, they are concatenated by the compiler:
class EmptyString {
public static void main(String[] args) {
String s = "any old string" + "";
}
}
javap -c EmptyString
:
Compiled from "EmptyString.java"
class EmptyString extends java.lang.Object{
EmptyString();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String any old string
2: astore_1
3: return
}