If you have something like this:
Collection<String> strings = ...;
String all = "";
for (String s : strings) all += s;
... then it's equivalent to:
Collection<String> strings = ...;
String all = "";
for (String s : strings) all = new StringBuilder(all).append(s).toString();
Each loops creates a new StringBuilder
which is essentially a copy of all
, appends a copy of s
to it, and then copies the result of the concatenation to a new String
. Obviously, using a single StringBuilder saves a lot of unnecessary allocations:
Collection<String> strings = ...;
StringBuilder sb = new StringBuilder();
for (String s : strings) sb.append(s);
String all = sb.toString();
As for x += y
versus x = x + y
, they compile to the same thing.
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;
}
}
Compile it with javac
, and then disassemble it with 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
}
Personally, I'd favor +=
because with it, you make a clearer statement of intent - "I want to add the content of b
to a
". Any variations in performance between the two forms are with a 100% certainty the result of something outside of your code (e.g., GC pauses, random cache misses or something like it).
Bad compilers might also have a slightly easier time to optimize the +=
form (which is irrelevant to you, since even if javac
would be crappy, HotSpot sure isn't).