Программирование - это инженерная дисциплина. В ней не может быть волшебных рецептов, работающих всегда и везде. Искусство инженера в поиске компромиссов, дающих наиболее выгодное сочетание качеств в конкретных ситуациях.
StringBuilder
даёт преимущество только при множестве операций на изменение строки. Например при наращивании строки в цикле. Во всех остальных случаях
StringBuilder
медленнее и требует больше памяти. Кроме того, он не является потокобезопасным, в отличии от строк.
Что касается оптимизации, компилятор заменяет конкатенации строк использованием метода
StringBuilder.append(), но только тогда, когда точно уверен, что это не изменит логику выполнения. Увидеть это легко. Возьмём такой код:
public class Example {
public static String concat(String s1, String s2) {
return s1 + s2;
}
public static void main(String[] args) {
System.out.println(concat("Hello ", "World"));
}
}
Скомпилируем
javac Example.java
И заглянем в получившийся байткод
javap -c Example
public static java.lang.String concat(java.lang.String, java.lang.String);
Code:
0: new #2 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_1
12: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn