una salto parte manejo linea funciones extraer declarar concatenar caracteres cadenas cadena java string concatenation string.format

salto - ¿Es una mejor práctica utilizar String.format sobre la concatenación de cadenas en Java?



manejo de cadenas en java (12)

¿Hay una diferencia perceptible entre el uso de String.Format y la concatenación de cadenas en Java?

String.format a usar String.format pero de vez en cuando se desliza y usa un concat. Me preguntaba si uno era mejor que el otro.

String.Format como lo veo, String.Format le da más poder para "formatear" la cadena; y la concatenación significa que no tiene que preocuparse por poner accidentalmente un% s extra o perder uno.

String.format también es más corto.

Cuál es más legible depende de cómo funciona tu cabeza.


Cuál es más legible depende de cómo funciona tu cabeza.

Tienes tu respuesta allí mismo.

Es una cuestión de gusto personal.

La concatenación de cuerdas es ligeramente más rápida, supongo, pero eso debería ser insignificante.


Aquí está la misma prueba que la anterior con la modificación de llamar al método toString () en el StringBuilder . Los resultados a continuación muestran que el enfoque de StringBuilder es un poco más lento que la concatenación de cadenas utilizando el operador + .

archivo: StringTest.java

class StringTest { public static void main(String[] args) { String formatString = "Hi %s; Hi to you %s"; long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { String s = String.format(formatString, i, +i * 2); } long end = System.currentTimeMillis(); System.out.println("Format = " + ((end - start)) + " millisecond"); start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { String s = "Hi " + i + "; Hi to you " + i * 2; } end = System.currentTimeMillis(); System.out.println("Concatenation = " + ((end - start)) + " millisecond"); start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { StringBuilder bldString = new StringBuilder("Hi "); bldString.append(i).append("Hi to you ").append(i * 2).toString(); } end = System.currentTimeMillis(); System.out.println("String Builder = " + ((end - start)) + " millisecond"); } }

Comandos de Shell: (compilar y ejecutar StringTest 5 veces)

> javac StringTest.java > sh -c "for i in /$(seq 1 5); do echo /"Run /${i}/"; java StringTest; done"

Resultados:

Run 1 Format = 1290 millisecond Concatenation = 115 millisecond String Builder = 130 millisecond Run 2 Format = 1265 millisecond Concatenation = 114 millisecond String Builder = 126 millisecond Run 3 Format = 1303 millisecond Concatenation = 114 millisecond String Builder = 127 millisecond Run 4 Format = 1297 millisecond Concatenation = 114 millisecond String Builder = 127 millisecond Run 5 Format = 1270 millisecond Concatenation = 114 millisecond String Builder = 126 millisecond


Aquí hay una prueba con múltiples tamaños de muestra en milisegundos.

public class Time { public static String sysFile = "/sys/class/camera/rear/rear_flash"; public static String cmdString = "echo %s > " + sysFile; public static void main(String[] args) { int i = 1; for(int run=1; run <= 12; run++){ for(int test =1; test <= 2 ; test++){ System.out.println( String.format("/nTEST: %s, RUN: %s, Iterations: %s",run,test,i)); test(run, i); } System.out.println("/n____________________________"); i = i*3; } } public static void test(int run, int iterations){ long start = System.nanoTime(); for( int i=0;i<iterations; i++){ String s = "echo " + i + " > "+ sysFile; } long t = System.nanoTime() - start; String r = String.format(" %-13s =%10d %s", "Concatenation",t,"nanosecond"); System.out.println(r) ; start = System.nanoTime(); for( int i=0;i<iterations; i++){ String s = String.format(cmdString, i); } t = System.nanoTime() - start; r = String.format(" %-13s =%10d %s", "Format",t,"nanosecond"); System.out.println(r); start = System.nanoTime(); for( int i=0;i<iterations; i++){ StringBuilder b = new StringBuilder("echo "); b.append(i).append(" > ").append(sysFile); String s = b.toString(); } t = System.nanoTime() - start; r = String.format(" %-13s =%10d %s", "StringBuilder",t,"nanosecond"); System.out.println(r); }

}

TEST: 1, RUN: 1, Iterations: 1 Concatenation = 14911 nanosecond Format = 45026 nanosecond StringBuilder = 3509 nanosecond TEST: 1, RUN: 2, Iterations: 1 Concatenation = 3509 nanosecond Format = 38594 nanosecond StringBuilder = 3509 nanosecond ____________________________ TEST: 2, RUN: 1, Iterations: 3 Concatenation = 8479 nanosecond Format = 94438 nanosecond StringBuilder = 5263 nanosecond TEST: 2, RUN: 2, Iterations: 3 Concatenation = 4970 nanosecond Format = 92976 nanosecond StringBuilder = 5848 nanosecond ____________________________ TEST: 3, RUN: 1, Iterations: 9 Concatenation = 11403 nanosecond Format = 287115 nanosecond StringBuilder = 14326 nanosecond TEST: 3, RUN: 2, Iterations: 9 Concatenation = 12280 nanosecond Format = 209051 nanosecond StringBuilder = 11818 nanosecond ____________________________ TEST: 5, RUN: 1, Iterations: 81 Concatenation = 54383 nanosecond Format = 1503113 nanosecond StringBuilder = 40056 nanosecond TEST: 5, RUN: 2, Iterations: 81 Concatenation = 44149 nanosecond Format = 1264241 nanosecond StringBuilder = 34208 nanosecond ____________________________ TEST: 6, RUN: 1, Iterations: 243 Concatenation = 76018 nanosecond Format = 3210891 nanosecond StringBuilder = 76603 nanosecond TEST: 6, RUN: 2, Iterations: 243 Concatenation = 91222 nanosecond Format = 2716773 nanosecond StringBuilder = 73972 nanosecond ____________________________ TEST: 8, RUN: 1, Iterations: 2187 Concatenation = 527450 nanosecond Format = 10291108 nanosecond StringBuilder = 885027 nanosecond TEST: 8, RUN: 2, Iterations: 2187 Concatenation = 526865 nanosecond Format = 6294307 nanosecond StringBuilder = 591773 nanosecond ____________________________ TEST: 10, RUN: 1, Iterations: 19683 Concatenation = 4592961 nanosecond Format = 60114307 nanosecond StringBuilder = 2129387 nanosecond TEST: 10, RUN: 2, Iterations: 19683 Concatenation = 1850166 nanosecond Format = 35940524 nanosecond StringBuilder = 1885544 nanosecond ____________________________ TEST: 12, RUN: 1, Iterations: 177147 Concatenation = 26847286 nanosecond Format = 126332877 nanosecond StringBuilder = 17578914 nanosecond TEST: 12, RUN: 2, Iterations: 177147 Concatenation = 24405056 nanosecond Format = 129707207 nanosecond StringBuilder = 12253840 nanosecond


En general, la concatenación de cadenas se debe String.format a String.format . Este último tiene dos desventajas principales:

  1. No codifica la cadena que se construirá de manera local.
  2. El proceso de construcción está codificado en una cadena.

Por punto 1, quiero decir que no es posible entender lo que está haciendo una llamada String.format() en un solo paso secuencial. Se obliga a uno a ir y venir entre la cadena de formato y los argumentos, mientras se cuenta la posición de los argumentos. Para concatenaciones cortas, esto no es un gran problema. En estos casos, sin embargo, la concatenación de cadenas es menos verbosa.

Por el punto 2, quiero decir que la parte importante del proceso de construcción está codificada en la cadena de formato (usando un DSL). Usar cadenas para representar el código tiene muchas desventajas. No es intrínsecamente seguro para los tipos y complica el resaltado de sintaxis, el análisis de código, la optimización, etc.

Por supuesto, cuando se usan herramientas o marcos externos al lenguaje Java, pueden entrar en juego nuevos factores.


No he hecho ningún punto de referencia específico, pero creo que la concatenación puede ser más rápida. String.format () crea un nuevo formateador que, a su vez, crea un nuevo StringBuilder (con un tamaño de solo 16 caracteres). Eso es una gran cantidad de gastos generales, especialmente si está formateando una cadena más larga y StringBuilder sigue teniendo que cambiar el tamaño.

Sin embargo, la concatenación es menos útil y más difícil de leer. Como siempre, vale la pena hacer una referencia en su código para ver cuál es mejor. Las diferencias pueden ser insignificantes en la aplicación del servidor después de que los paquetes de recursos, las configuraciones regionales, etc. se carguen en la memoria y el código esté JITted.

Tal vez, como práctica recomendada, sería una buena idea crear su propio Formateador con un StringBuilder (Anexable) y una configuración regional del tamaño adecuado y usarlo si tiene mucho formato para hacer.


No puede comparar Strat Concatenation y String.Format por el programa anterior.

Puede intentar esto también intercambiando la posición de usar su String.Format y Concatenation en su bloque de código como el siguiente

public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); for( int i=0;i<1000000; i++){ String s = String.format( "Hi %s; Hi to you %s",i, + i*2); } long end = System.currentTimeMillis(); System.out.println("Format = " + ((end - start)) + " millisecond"); start = System.currentTimeMillis(); for( int i=0;i<1000000; i++){ String s = "Hi " + i + "; Hi to you " + i*2; } end = System.currentTimeMillis(); System.out.println("Concatenation = " + ((end - start)) + " millisecond") ; }

Te sorprenderá ver que el Formato funciona más rápido aquí. Esto se debe a que los objetos iniciales creados pueden no ser liberados y puede haber un problema con la asignación de memoria y, por lo tanto, con el rendimiento.


Podría haber una diferencia perceptible.

String.format es bastante complejo y utiliza una expresión regular debajo, así que no hagas el hábito de usarlo en todas partes, sino solo donde lo necesites.

StringBuilder sería un orden de magnitud más rápido (como alguien señalado aquí).


Sobre el rendimiento:

public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); for(int i = 0; i < 1000000; i++){ String s = "Hi " + i + "; Hi to you " + i*2; } long end = System.currentTimeMillis(); System.out.println("Concatenation = " + ((end - start)) + " millisecond") ; start = System.currentTimeMillis(); for(int i = 0; i < 1000000; i++){ String s = String.format("Hi %s; Hi to you %s",i, + i*2); } end = System.currentTimeMillis(); System.out.println("Format = " + ((end - start)) + " millisecond"); }

Los resultados del tiempo son los siguientes:

  • Concatenación = 265 milisegundos
  • Formato = 4141 milisegundos

Por lo tanto, la concatenación es mucho más rápida que String.format.


Sugeriría que es una mejor práctica usar String.format() . La razón principal es que String.format() se puede localizar más fácilmente con texto cargado desde archivos de recursos, mientras que la concatenación no se puede localizar sin producir un nuevo ejecutable con un código diferente para cada idioma.

Si planea que su aplicación sea localizable, también debe adquirir el hábito de especificar posiciones de argumentos para sus tokens de formato también:

"Hello %1$s the time is %2$t"

Esto puede ser localizado y se pueden intercambiar los tokens de nombre y tiempo sin requerir una recompilación del ejecutable para tener en cuenta el orden diferente. Con las posiciones de argumento, también puede reutilizar el mismo argumento sin pasarlo a la función dos veces:

String.format("Hello %1$s, your name is %1$s and the time is %2$t", name, time)


Un problema con .format es que se pierde la seguridad de tipo estático. Puede tener muy pocos argumentos para su formato, y puede tener los tipos incorrectos para los especificadores de formato, lo que lleva a una IllegalFormatException en tiempo de ejecución , por lo que podría terminar con un código de registro que interrumpa la producción.

En contraste, los argumentos a + pueden ser probados por el compilador.


Ya que hay una discusión sobre el rendimiento, pensé que agregaría en una comparación que incluía StringBuilder. De hecho, es más rápido que el Concat y, naturalmente, la opción String.format.

Para hacer de este un tipo de comparación manzanas con manzanas, instalo un nuevo StringBuilder en el bucle en lugar de hacerlo en el exterior (esto es en realidad más rápido que hacer solo una instancia, probablemente debido a la sobrecarga de reasignación de espacio para el bucle adjunto al final de un constructor).

String formatString = "Hi %s; Hi to you %s"; long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { String s = String.format(formatString, i, +i * 2); } long end = System.currentTimeMillis(); log.info("Format = " + ((end - start)) + " millisecond"); start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { String s = "Hi " + i + "; Hi to you " + i * 2; } end = System.currentTimeMillis(); log.info("Concatenation = " + ((end - start)) + " millisecond"); start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { StringBuilder bldString = new StringBuilder("Hi "); bldString.append(i).append("; Hi to you ").append(i * 2); } end = System.currentTimeMillis(); log.info("String Builder = " + ((end - start)) + " millisecond");

  • 2012-01-11 16: 30: 46,058 INFO [TestMain] - Formato = 1416 milisegundos
  • 2012-01-11 16: 30: 46,190 INFO [TestMain] - Concatenación = 134 milisegundos
  • 2012-01-11 16: 30: 46,313 INFO [TestMain] - Generador de cadenas = 117 milisegundos

String.format() es algo más que concatenar cadenas. Por ejemplo, puede mostrar números en una configuración regional específica utilizando String.format() .

Sin embargo, si no te importa la localización, no hay diferencia funcional. Tal vez el uno sea más rápido que el otro, pero en la mayoría de los casos será despreciable.