Supongamos que hay una cadena, haremos muchas operaciones de empalme de bucles en esta cadena, usando "+" obtendremos el rendimiento más bajo. ¿Pero qué tan mala es esta actuación? ¿Cuál sería el resultado si también pusiéramos StringBuffer, StringBuilder o String.concat() en la prueba de rendimiento? ¡Este artículo dará respuesta a estas preguntas!
Usaremos Per4j para calcular el rendimiento, porque esta herramienta puede brindarnos un conjunto completo de indicadores de rendimiento, como el tiempo mínimo y máximo empleado, la desviación estándar del período de tiempo estadístico, etc. En el código de prueba, para obtener un valor de desviación estándar preciso, realizaremos una prueba de 20 empalmes "*" 50.000 veces. Este es el método que usaremos para concatenar cadenas:
Copie el código de código de la siguiente manera:
Operador de concatenación (+)
Método concat de cadena concat (String str)
Método de agregar StringBuffer agregar (String str)
Método de adición de StringBuilder agregar (String str)
Finalmente, veremos el código de bytes para ver cómo se ejecutan exactamente estos métodos. Ahora, comencemos creando nuestra clase. Tenga en cuenta que para calcular el rendimiento de cada bucle, cada código de prueba en el código debe incluirse en la biblioteca Per4J. Primero definimos el número de iteraciones.
Copie el código de código de la siguiente manera:
int final estático privado OUTER_ITERATION=20;
int final estático privado INNER_ITERATION=50000;
A continuación, utilizaremos los 4 métodos anteriores para implementar nuestro código de prueba.
Copie el código de código de la siguiente manera:
Cadena addTestStr = "";
Cadena concatTestStr = "";
StringBuffer concatTestSb = nulo;
StringBuilder concatTestSbu = nulo;
para (int índiceexterior=0;índiceexterno<=OUTER_ITERATION;índiceexterno++) {
StopWatch stopWatch = new LoggingStopWatch("StringAddConcat");
addTestStr = "";
para (int internalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
addTestStr += "*";
stopWatch.stop();
}
para (int índiceexterior=0;índiceexterno<=OUTER_ITERATION;índiceexterno++) {
StopWatch stopWatch = new LoggingStopWatch("StringConcat");
concatTestStr = "";
para (int internalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestStr.concat("*");
stopWatch.stop();
}
para (int índiceexterior=0;índiceexterno<=OUTER_ITERATION;índiceexterno++) {
StopWatch stopWatch = new LoggingStopWatch("StringBufferConcat");
concatTestSb = nuevo StringBuffer();
para (int internalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSb.append("*");
stopWatch.stop();
}
para (int índiceexterior=0;índiceexterno<=OUTER_ITERATION;índiceexterior++) {
StopWatch stopWatch = new LoggingStopWatch("StringBuilderConcat");
concatTestSbu = nuevo StringBuilder();
para (int internalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSbu.append("*");
stopWatch.stop();
}
Luego ejecute el programa para generar métricas de rendimiento. Mi entorno operativo es un sistema operativo Windows 7 de 64 bits, una máquina JVM (7-ea) de 32 bits con 4 GB de memoria y una CPU Quad de doble núcleo a 2,00 GHz.
Resultó perfecto como lo imaginábamos. Lo único interesante es por qué String.concat también es muy bueno. Todos sabemos que String es una clase constante (una clase que no cambiará después de la inicialización), entonces, ¿por qué el rendimiento de concat es mejor? (Nota del traductor: de hecho, hay un problema con el código de prueba del autor original. El código de prueba para el método concat() debe escribirse como concatTestStr=concatTestStr.concat(“*”).) Para responder a esto Pregunta, deberíamos mirar la descompilación de concat. Sale el código de bytes. El paquete de descarga de este artículo contiene todos los códigos de bytes, pero ahora echemos un vistazo a este fragmento de código de concat:
Copie el código de código de la siguiente manera:
46: nuevo #6; //clase java/lang/StringBuilder
49: doble
50: invokespecial #7; //Método java/lang/StringBuilder."<init>":()V
53: carga_1
54: invocarvirtual #8; //Método java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: ldc #9; //Cadena *
59: invocarvirtual #8; //Método java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
62: invocarvirtual #10; //Método java/lang/StringBuilder.toString:()
Ljava/idioma/Cadena;
65: astore_1
66: iinc 7, 1
69: ir a 38
Este código es el código de bytes de String.concat (). A partir de este código, podemos ver claramente que el método concat () usa StringBuilder. El rendimiento de concat () debería ser tan bueno como el de StringBuilder, pero debido a la creación adicional de StringBuilder y. hacer la operación .append(str).append(str).toString() afectará el rendimiento de concate, por lo que StringBuilder y String Los tiempos de cancate son 1,8 y 3,3.
Por lo tanto, incluso al realizar la concatenación más simple, si no queremos crear una instancia de StringBuffer o StringBuilder, debemos usar concat. Pero para una gran cantidad de operaciones de empalme de cadenas, no debemos usar concat (Nota del traductor: debido a que el código de prueba no es completamente equivalente en función, el tiempo de procesamiento promedio de concat en el código de prueba reemplazado es 1650,9 milisegundos. Este resultado está en el comentario de texto original. ), porque concat reducirá el rendimiento de su programa y consumirá su CPU. Por lo tanto, para obtener el mayor rendimiento sin considerar la seguridad y la sincronización de los subprocesos, deberíamos intentar utilizar StringBuilder.