Performance comparison of String
concatenation versus StringBuilder John Dalbey Partner: Ian Anderson November 6, 2012 CPE 103-00 Statement of ObjectiveIn his book Effective Java, Joshua Bloch warns against using the String concatenation operator for repeated string concatentations. For once-only use likeSystem.out.println("Result:" + total + " years"); there's no problem. But using a statement like this: result = result + "word"; in a loop will invoke a severe performance penalty. Bloch recommends using Java's StringBuilder class as a much faster alternative. The purpose of this experiment is to see if String concatenation is really as bad as Bloch says it is, and if so, to determine if StringBuilder is really any better. TheoryBloch explains that since String is immutable, it can't simply append "word" to result, but that it has to make a copy of both operands then combine them and create a new string to hold the result. The copy operation is very expensive; he asserts that it is a quadratic time operation. So in theory we should expect to see the performance of StringBuilder is much faster than String.Description of Experimental SetupThe experiments were performed on a desktop workstation with 3 GB RAM and a Dual Core Processor running at 2.6GHz.ProcedureWe wrote a small program that implements both techniques. One method, concat(), uses a loop to repeat a String concatentation operation a given number of times. A second method, concatFast() uses StringBuilder. We wrote a main method that calls them inside a loop that provides an increasing limit for the number of concatentations, so several experimental trials can be run automatically.The core of the concat() method builds a string using the concatenation operator "+=". The concatFast() on the other hand, uses StringBuilder's append() method. We chose an arbitrary length of 80 characters for the string to be appended.
The complete program code is provided in the appendix. DataWe ran the program three times and averaged the observed times. The following table summarizes the running times for increasing number of items.Average run times in seconds.
Analysis of DataTo visualize the data, we created this chart of runtimes:Discussion of ResultsThe results we obtained confirm Bloch's prediction. The graph definitely shows that the String concatenation run times are quadratic. There is a clear exponential rate of increase in run time as the number of concatenations gets larger. The difference when compared with StringBuilder is quite dramatic.ConclusionsDue to the immutable nature of Java's String class, our experiment indicates that one should use caution when using the concatenation operator. It can produce surprisingly long runtimes in seemingly benign usage. Bloch recommends the StringBuilder class as the preferred alternative for doing any string manipulation operations, and our study supports his advice.AppendicesHere is the complete source code for our program./** * Experiment with string concatentation versus StringBuilder * Reference: Bloch, Effective Java, Item 51 (pg 227). * @author J. Dalbey * @version 11/6/12 */ public class StringTiming { static String sentence = "0123456789012345678901234" + "0123456789012345678901234" + "0123456789012345678901234" + "0123456789012345678901234"; // String concatenation public static String concat(int numItems) { String result=""; for (int i=0; i < numItems; i++) { result += sentence; } return result; } // StringBuilder append() public static String concatFast(int numItems) { StringBuilder builder = new StringBuilder(); for (int i=0; i < numItems; i++) { builder.append(sentence); } return builder.toString(); } public static void main(String[] args) { // Run several experimental trials for (int numItems = 1000; numItems<=15000; numItems += 1000) { System.out.println("Number of Items: " + numItems); long starttime = System.currentTimeMillis(); concat(numItems); long endtime = System.currentTimeMillis(); System.out.println(" concat() elapsed time (secs): " + (endtime - starttime)/1000.0); starttime = System.currentTimeMillis(); concatFast(numItems); endtime = System.currentTimeMillis(); System.out.println(" concatFast() elapsed time (secs): " + (endtime - starttime)/1000.0); } } } Here is the raw program output for the three trials: Trial #1 Number of Items: 1000 concat() elapsed time (secs): 0.285 concatFast() elapsed time (secs): 0.0020 Number of Items: 2000 concat() elapsed time (secs): 1.378 concatFast() elapsed time (secs): 0.0080 Number of Items: 3000 concat() elapsed time (secs): 3.406 concatFast() elapsed time (secs): 0.0030 Number of Items: 4000 concat() elapsed time (secs): 6.301 concatFast() elapsed time (secs): 0.0040 Number of Items: 5000 concat() elapsed time (secs): 10.038 concatFast() elapsed time (secs): 0.0060 Number of Items: 6000 concat() elapsed time (secs): 14.557 concatFast() elapsed time (secs): 0.0060 Number of Items: 7000 concat() elapsed time (secs): 19.91 concatFast() elapsed time (secs): 0.0070 Number of Items: 8000 concat() elapsed time (secs): 26.088 concatFast() elapsed time (secs): 0.0070 Number of Items: 9000 concat() elapsed time (secs): 33.099 concatFast() elapsed time (secs): 0.012 Number of Items: 10000 concat() elapsed time (secs): 40.913 concatFast() elapsed time (secs): 0.012 Number of Items: 11000 concat() elapsed time (secs): 49.612 concatFast() elapsed time (secs): 0.014 Number of Items: 12000 concat() elapsed time (secs): 59.07 concatFast() elapsed time (secs): 0.013 Number of Items: 13000 concat() elapsed time (secs): 69.38 concatFast() elapsed time (secs): 0.014 Number of Items: 14000 concat() elapsed time (secs): 80.6 concatFast() elapsed time (secs): 0.014 Number of Items: 15000 concat() elapsed time (secs): 94.295 concatFast() elapsed time (secs): 0.014 Trial #2 Number of Items: 1000 concat() elapsed time (secs): 0.429 concatFast() elapsed time (secs): 0.0020 Number of Items: 2000 concat() elapsed time (secs): 1.548 concatFast() elapsed time (secs): 0.0020 Number of Items: 3000 concat() elapsed time (secs): 3.496 concatFast() elapsed time (secs): 0.0030 Number of Items: 4000 concat() elapsed time (secs): 6.504 concatFast() elapsed time (secs): 0.0030 Number of Items: 5000 concat() elapsed time (secs): 10.24 concatFast() elapsed time (secs): 0.0080 Number of Items: 6000 concat() elapsed time (secs): 14.745 concatFast() elapsed time (secs): 0.0080 Number of Items: 7000 concat() elapsed time (secs): 20.264 concatFast() elapsed time (secs): 0.0070 Number of Items: 8000 concat() elapsed time (secs): 26.487 concatFast() elapsed time (secs): 0.0080 Number of Items: 9000 concat() elapsed time (secs): 33.603 concatFast() elapsed time (secs): 0.014 Number of Items: 10000 concat() elapsed time (secs): 41.547 concatFast() elapsed time (secs): 0.012 Number of Items: 11000 concat() elapsed time (secs): 53.547 concatFast() elapsed time (secs): 0.012 Number of Items: 12000 concat() elapsed time (secs): 66.752 concatFast() elapsed time (secs): 0.013 Number of Items: 13000 concat() elapsed time (secs): 70.83 concatFast() elapsed time (secs): 0.017 Number of Items: 14000 concat() elapsed time (secs): 81.976 concatFast() elapsed time (secs): 0.018 Number of Items: 15000 concat() elapsed time (secs): 93.952 concatFast() elapsed time (secs): 0.022 Trial #3 Number of Items: 1000 concat() elapsed time (secs): 0.341 concatFast() elapsed time (secs): 0.0 Number of Items: 2000 concat() elapsed time (secs): 1.397 concatFast() elapsed time (secs): 0.0020 Number of Items: 3000 concat() elapsed time (secs): 3.517 concatFast() elapsed time (secs): 0.0030 Number of Items: 4000 concat() elapsed time (secs): 6.541 concatFast() elapsed time (secs): 0.0040 Number of Items: 5000 concat() elapsed time (secs): 10.211 concatFast() elapsed time (secs): 0.0050 Number of Items: 6000 concat() elapsed time (secs): 14.714 concatFast() elapsed time (secs): 0.0070 Number of Items: 7000 concat() elapsed time (secs): 20.2 concatFast() elapsed time (secs): 0.0080 Number of Items: 8000 concat() elapsed time (secs): 26.524 concatFast() elapsed time (secs): 0.0080 Number of Items: 9000 concat() elapsed time (secs): 33.911 concatFast() elapsed time (secs): 0.014 Number of Items: 10000 concat() elapsed time (secs): 42.346 concatFast() elapsed time (secs): 0.012 Number of Items: 11000 concat() elapsed time (secs): 51.229 concatFast() elapsed time (secs): 0.016 Number of Items: 12000 concat() elapsed time (secs): 60.127 concatFast() elapsed time (secs): 0.013 Number of Items: 13000 concat() elapsed time (secs): 70.3 concatFast() elapsed time (secs): 0.013 Number of Items: 14000 concat() elapsed time (secs): 82.225 concatFast() elapsed time (secs): 0.017 Number of Items: 15000 concat() elapsed time (secs): 93.527 concatFast() elapsed time (secs): 0.018 |