This is a common question and there are 2 answers to it:
The key to understanding this is to understand how the Java compiler handles string concatenation. If you compile the following code:
for ( int i = 0; i < scores.length; ++i ) { allScores += scores[i] + ", "; }
And then view the generated p code using the javap command you will see the following:
0: iconst_0 1: istore_2 2: iload_2 3: aload_1 4: arraylength 5: if_icmpge 40 8: new #4; //class java/lang/StringBuilder 11: dup 12: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V 15: aload_0 16: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: aload_1 20: iload_2 21: iaload 22: invokevirtual #12; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 25: ldc #13; //String , 27: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 30: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 33: astore_0 34: iinc 2, 1 37: goto 2
This output may not make much sense to you but the javap command handly adds comments showing which methods are being called. Looking at the comments shows that for every iteration of the loop a new StringBuilder object is being created, 3 strings are appended to it and then the StringBuilder is converted back to a String.
StringBuilder sb = new StringBuilder(allScores); for ( int i = 0; i < scores.length; ++i ) { sb.append(scores[i]); sb.append(", "); } allScores = sb.toString();
And looking at the generated p code you will see there is now only one StringBuilder object created, 2 calls to append() within the loop and one call to toString() after the loop:
0: new #4; //class java/lang/StringBuilder 3: dup 4: aload_0 5: invokespecial #14; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 8: astore_2 9: iconst_0 10: istore_3 11: iload_3 12: aload_1 13: arraylength 14: if_icmpge 36 17: aload_2 18: aload_1 19: iload_3 20: iaload 21: invokevirtual #12; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 24: ldc #13; //String , 26: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 29: pop 30: iinc 3, 1 33: goto 11 36: aload_2 37: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 40: astore_0
So the second approach is likely to be more efficient than the first example, but by how much?
The answer to that is a little surprising. If we write a simple test program to time both approaches we can get some idea of the relative efficiency of each approach. For example:
static void test() { String text = ""; // warm up system for ( int i = 0; i < 10000; ++i ) text = text + "*"; System.out.println("Running concatenation time test..."); text = ""; long t = System.currentTimeMillis(); for ( int i = 0; i < 500000; ++i ) text = text + "*"; System.out.println("Concatenate strings - time = "+(System.currentTimeMillis()-t)+"ms, string length = "+text.length()); text = ""; t = System.currentTimeMillis(); StringBuilder sb = new StringBuilder(text); // warm up system for ( int i = 0; i < 10000; ++i ) sb.append("*"); sb = new StringBuilder(text); for ( int i = 0; i < 500000; ++i ) sb.append("*"); text = sb.toString(); System.out.println("Using StringBuilder - time = "+(System.currentTimeMillis()-t)+"ms, string length = "+text.length()); }
On my system this produces the following output, you may have to adjust the number of iterations to produce reasonable output values on your system.
Running concatenation time test... Concatenate strings - time = 2297953ms, string length = 500000 Using StringBuilder - time = 31ms, string length = 500000
Yes, approach two really is approximately 74,000 times quicker in this example.
In the first approach for every iteration of the loop a new StringBuilder object is created and all of the characters in the String have to be copied into the object. Then, once the additional text has been appended, a new String object is created and again all the characters have to be copied. Now when the String only holds a few characters this takes very little time but as the String grows in length copying of all the characters twice for each iteration becomes increasingly time consuming, not to mention the increased probability of garbage collection cycles. A good way to see how approach one becomes increasingly inefficient as the length of the String increases is to run the following code and see how much the rate of printing slows down once as the String length grows.
for ( int i = 0; i < 500000; ++i ) { text = text + "*"; // print a message every thousand iterations if ( i%1000 == 0 ) System.out.println("Iteration "+i+", String length = "+text.length()); }