我只是想弄清楚分配值的最快方法是
somevar+=1;
要么
somevar=somevar+1;
以前,在使用文本而不是整数的情况下,我遇到了使用
text+="sometext"
而不是text.append("sometext")
或text=text+"sometext"
的性能下降的问题,问题是我再也找不到用于注释的源代码了。那么理论上最快的方法是什么?代码背景几乎实时地设置成一个快速循环。
最佳答案
如果您有这样的事情:
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
的副本附加到其后,然后将串联结果复制到新的x += y
中。显然,使用单个StringBuilder可以节省很多不必要的分配:Collection<String> strings = ...;
StringBuilder sb = new StringBuilder();
for (String s : strings) sb.append(s);
String all = sb.toString();
至于
x = x + y
与javac
,它们可以编译为相同的东西。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;
}
}
使用
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肯定不是)。