¿Es una mejor práctica usar String.format sobre string Concatenation en Java?

¿Existe 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 me deslizaré y String.format un concat. Me preguntaba si uno era mejor que el otro.

De la forma en que lo veo, String.Format te da más poder para “formatear” la cadena; y la concatenación significa que no tiene que preocuparse de 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.

    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 código diferente para cada idioma.

    Si planeas que tu aplicación sea localizable, también debes adquirir el hábito de especificar posiciones de argumento para tus tokens de formato:

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

    Esto puede ser localizado y tener los tokens de nombre y tiempo intercambiados sin requerir una recomstackción del ejecutable para dar cuenta de los diferentes pedidos. Con posiciones de argumento también puede volver a utilizar 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) 

    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 de tiempo son los siguientes:

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

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

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

    Para hacer de esto una especie de comparación de manzanas con manzanas, instalé un nuevo StringBuilder en el bucle en lugar de hacerlo afuera (esto es más rápido que hacer solo una instanciación muy probablemente debido a la sobrecarga de reasignar espacio para el anexo de bucle 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

    Un problema con .format es que pierde 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 puede terminar con un código de inicio de sesión que interrumpe la producción.

    Por el contrario, los argumentos a + pueden ser probados por el comstackdor.

    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 cadenas es marginalmente más rápida, supongo, pero eso debería ser insignificante.

    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 "+ 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 ").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 

    Aquí está la misma prueba que la anterior con la modificación de llamar al método toString () en StringBuilder . Los resultados a continuación muestran que el enfoque de StringBuilder es un poco más lento que la concatenación de cadenas con 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: (comstackr 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 

    String.format() es más que simplemente concatenar cadenas. Por ejemplo, puede visualizar 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. Quizás el uno es más rápido que el otro, pero en la mayoría de los casos será insignificante.

    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). Esa es una gran cantidad de sobrecarga, 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 un punto de referencia en su código para ver cuál es mejor. Las diferencias pueden ser insignificantes en la aplicación de servidor una vez que sus paquetes de recursos, configuraciones regionales, etc. se cargan en la memoria y el código está JITted.

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

    Podría haber una diferencia perceptible.

    String.format es bastante complejo y usa una expresión regular debajo, así que no hagas un 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 aquí ya señaló).

    En general, la concatenación de cadenas debe String.format sobre String.format . El ú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.

    En el punto 1, quiero decir que no es posible entender lo que hace un String.format() en un solo pase secuencial. Uno se ve obligado a ir y venir entre la cadena de formato y los argumentos, mientras cuenta la posición de los argumentos. Para concatenaciones cortas, esto no es un gran problema. Sin embargo, en estos casos, la concatenación de cadenas es menos detallada.

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

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

    No puede comparar Cadena de cadenas y Cadena.Formato según el progtwig 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 Format 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 el rendimiento.