如果你有这样的事情:
Collection<String> strings = ...;
String all = "";
for (String s : strings) all += s;
...那么就相当于:
Collection<String> strings = ...;
String all = "";
for (String s : strings) all = new StringBuilder(all).append(s).toString();
每个循环都会创建一个新的StringBuilder,它本质上是all 的副本,将s 的副本附加到它,然后将连接的结果复制到一个新的String。显然,使用单个 StringBuilder 可以节省很多不必要的分配:
Collection<String> strings = ...;
StringBuilder sb = new StringBuilder();
for (String s : strings) sb.append(s);
String all = sb.toString();
对于x += y 和x = x + y,它们编译成相同的东西。
class Concat {
public String concat1(String a, String b) {
a += b;
return a;
}
public String concat2(String a, String b) {
a = a + b;
return a;
}
}
用javac编译,然后用javap反汇编:
$ javap -c Concat
Compiled from "Concat.java"
class Concat extends java.lang.Object{
Concat();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public java.lang.String concat1(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_1
8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
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: astore_1
19: aload_1
20: areturn
public java.lang.String concat2(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_1
8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
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: astore_1
19: aload_1
20: areturn
}
就个人而言,我更喜欢+=,因为有了它,您可以更清楚地表达意图——“我想将b 的内容添加到a”。两种形式之间的任何性能差异都 100% 确定是代码之外的结果(例如,GC 暂停、随机缓存未命中或类似情况)。
糟糕的编译器也可能更容易优化+= 表单(这与您无关,因为即使javac 很糟糕,HotSpot 肯定不会)。