Suppose there is a string, we will do a lot of loop splicing operations on this string, using "+" will get the lowest performance. But how bad is this performance? What would be the result if we also put StringBuffer, StringBuilder or String.concat() into the performance test? This article will give an answer to these questions!
We will use Per4j to calculate performance, because this tool can give us a complete set of performance indicators, such as the minimum and maximum time taken, the standard deviation of the statistical time period, etc. In the test code, in order to get an accurate standard deviation value, we will perform a test of 20 splicing "*" 50,000 times. Here is the method we will use to concatenate strings:
Copy the code code as follows:
Concatenation Operator (+)
String concat method concat(String str)
StringBuffer append method append(String str)
StringBuilder append method append(String str)
Finally, we'll look at the bytecode to see how exactly these methods are executed. Now, let's start by creating our class. Note that in order to calculate the performance of each loop, each test code in the code needs to be wrapped with the Per4J library. First we define the number of iterations
Copy the code code as follows:
private static final int OUTER_ITERATION=20;
private static final int INNER_ITERATION=50000;
Next, we will use the above 4 methods to implement our test code.
Copy the code code as follows:
String addTestStr = "";
String concatTestStr = "";
StringBuffer concatTestSb = null;
StringBuilder concatTestSbu = null;
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringAddConcat");
addTestStr = "";
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
addTestStr += "*";
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringConcat");
concatTestStr = "";
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestStr.concat("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBufferConcat");
concatTestSb = new StringBuffer();
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSb.append("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBuilderConcat");
concatTestSbu = new StringBuilder();
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSbu.append("*");
stopWatch.stop();
}
Next run the program to generate performance metrics. My operating environment is a 64-bit Windows 7 operating system, a 32-bit JVM (7-ea) machine with 4GB memory and a dual-core Quad 2.00GHz CPU.
It turned out perfectly as we imagined. The only interesting thing is why String.concat is also very good. We all know that String is a constant class (a class that will not change after initialization), so why is the performance of concat better? (Translator’s Note: In fact, there is a problem with the test code of the original author. The test code for the concat() method should be written as concatTestStr=concatTestStr.concat(“*”).) In order to answer this question, we should look at concat decompilation The bytecode comes out. The download package of this article contains all the bytecodes, but now let’s take a look at this code snippet of concat:
Copy the code code as follows:
46: new #6; //class java/lang/StringBuilder
49: dup
50: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V
53: aload_1
54: invokevirtual #8; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: ldc #9; //String *
59: invokevirtual #8; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
62: invokevirtual #10; //Method java/lang/StringBuilder.toString:()
Ljava/lang/String;
65: astore_1
66: iinc 7, 1
69: goto 38
This code is the bytecode of String.concat(). From this code, we can clearly see that the concat() method uses StringBuilder. The performance of concat() should be as good as StringBuilder, but due to the additional Creating StringBuilder and doing .append(str).append(str).toString() operation will affect the performance of concate, so StringBuilder and String Cancate times are 1.8 and 3.3.
Therefore, even when doing the simplest concatenation, if we don't want to create a StringBuffer or StringBuilder instance, we should use concat. But for a large number of string splicing operations, we should not use concat (Translator's Note: Because the test code is not completely equivalent in function, the average processing time of concat in the replaced test code is 1650.9 milliseconds. This result is in the original text comment. ), because concat will reduce the performance of your program and consume your CPU. Therefore, in order to obtain the highest performance without considering thread safety and synchronization, we should try to use StringBuilder.