我只是想弄清楚分配值的最快方法是

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 + yjavac,它们可以编译为相同的东西。

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肯定不是)。

10-07 19:03
查看更多