java – StringBuilder vs. . Concat vs. “is the relative performance of operators in eclipse different from the command line?
I'm reading about how, where possible, the java compiler will compile strings connected with the '' operator to an instance of StringBuilder, and how to make them better use the simple '' operator because they are compile to the same code (except when you are building a while loop, in this case, it is obviously best to use StringBuilder.)
I've also read this string The concat method is the worst choice all the time (so many, so it was modified to an error findbugs!)
So I decided to write a Java class in eclipse myself My results surprised me and I found that different methods are faster or slower if I follow and run them at eclipses and command lines
First of all, the result of my solar eclipse is:
the total millis to concatenate with + was: 12154 the total millis to concatenate with .concat was: 8840 the total millis to concatenate with StringBuilder was: 11350 the total millis to concatenate with StringBuilder with a specified size was: 5611
Therefore, in the string builder of eclipse, the specified size is the fastest, followed by Concat (strange), then StringBuilder and "" connection are almost the same
However, my result on the command line is:
the total millis to concatenate with + was: 4139 the total millis to concatenate with .concat was: 8590 the total millis to concatenate with StringBuilder was: 10888 the total millis to concatenate with StringBuilder with a specified size was: 6033
Therefore, when I compile and run from the commnad line, the "" operator is obviously the fastest, followed by the size of string builder, then concat, and finally the normal StringBuilder!
It means nothing to me Obviously, all the stackoverflow answers I read say that operators compiled into normal old StringBuilder instances must be outdated
Does anyone know what really happened here?
I'm using jdk1 7.0_ 07, as long as I can tell eclipse and my command line reference exactly the same one The only difference I know is to use "javaw", but from what I see, it shouldn't make a difference
This is my test class, if you want to verify that I didn't do anything wrong, but I'm sure it's solid
public class Test { static final int LOOPS = 100000000; static final String FIRST_STRING = "This is such"; static final String SECOND_STRING = " an awesomely cool "; static final String THIRD_STRING = "to write string."; /** * @param args */ public static void main(String[] args) { Test.plusOperator(); Test.dotConcat(); Test.stringBuilder(); Test.stringBuilderSizeSpecified(); } public static void plusOperator() { String localOne = FIRST_STRING; String localTwo = SECOND_STRING; String localThree = THIRD_STRING; Calendar startTime = Calendar.getInstance(); for (int x = 0; x < LOOPS; x++) { String toPrint = localOne + localTwo + localThree; } Calendar endTime = Calendar.getInstance(); System.out.println("the total millis to concatenate with + was: " + (endTime.getTimeInMillis() - startTime.getTimeInMillis())); } public static void stringBuilder() { String localOne = FIRST_STRING; String localTwo = SECOND_STRING; String localThree = THIRD_STRING; Calendar startTime = Calendar.getInstance(); for (int x = 0; x < LOOPS; x++) { StringBuilder toBuild = new StringBuilder() .append(localOne) .append(localTwo) .append(localThree); } Calendar endTime = Calendar.getInstance(); System.out.println("the total millis to concatenate with StringBuilder was: " + (endTime.getTimeInMillis() - startTime.getTimeInMillis())); } public static void stringBuilderSizeSpecified() { String localOne = FIRST_STRING; String localTwo = SECOND_STRING; String localThree = THIRD_STRING; Calendar startTime = Calendar.getInstance(); for (int x = 0; x < LOOPS; x++) { StringBuilder toBuild = new StringBuilder(50) .append(localOne) .append(localTwo) .append(localThree); } Calendar endTime = Calendar.getInstance(); System.out.println("the total millis to concatenate with StringBuilder with a specified size was: " + (endTime.getTimeInMillis() - startTime.getTimeInMillis())); } public static void dotConcat() { String localOne = FIRST_STRING; String localTwo = SECOND_STRING; String localThree = THIRD_STRING; Calendar startTime = Calendar.getInstance(); for (int x = 0; x < LOOPS; x++) { String toPrint = localOne.concat(localTwo).concat(localThree); } Calendar endTime = Calendar.getInstance(); System.out.println("the total millis to concatenate with .concat was: " + (endTime.getTimeInMillis() - startTime.getTimeInMillis())); } }
Solution
In Oracle JDK 1.7 (javac 1.7.0_17), the '' operator is still implemented using StringBuilder, as shown by running javap - C on the class to get the bytecode (only the loop is shown here):
public static void plusOperator(); Code: 16: iload 4 18: ldc #10 // int 100000000 20: if_icmpge 53 23: new #11 // class java/lang/StringBuilder 26: dup 27: invokespecial #12 // Method java/lang/StringBuilder."<init>":()V 30: aload_0 31: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 34: aload_1 35: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 38: aload_2 39: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 42: invokevirtual #14 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 45: astore 5 47: iinc 4,1 50: goto 16 public static void stringBuilder(); Code: 16: iload 4 18: ldc #10 // int 100000000 20: if_icmpge 50 23: new #11 // class java/lang/StringBuilder 26: dup 27: invokespecial #12 // Method java/lang/StringBuilder."<init>":()V 30: aload_0 31: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 34: aload_1 35: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 38: aload_2 39: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 42: astore 5 44: iinc 4,1 47: goto 16
The only difference between the two is that the version with '' converts StringBuilder to a string in a loop
So the question becomes: why do your tests show such different results for the same code Or more completely, why is this not an effective micro benchmark Here are some possible reasons:
You are counting the clock This means that you are actually measuring everything the JVM does while running the test This includes garbage collection (which is important because you are creating a lot of garbage) You can alleviate this problem by getting thread CPU time. > You will not verify when or when hotspot is compiling methods That's why you should do a warm-up phase before any micro benchmark: basically, run main () multiple times before running your actual test