2012-03-20 18 views
9

Estaba creando un registrador en mi aplicación java (con NetBeans como IDE) cuando de repente vi una advertencia que decía: "Uso ineficaz de la concatenación de cadenas en el registrador".Uso ineficiente de la concatenación de cadenas

Mi código oringinal es

srcLogger.getLogger().log(Level.INFO,"UploadBean.doUpload completado [" + file.getName() + "]\n"); 

pero NetBeans sugerido para convertirlo en una plantilla que da este código (lo que es una "plantilla" significa aquí?):

srcLogger.getLogger().log(Level.INFO, "UploadBean.doUpload completado [{0}]\n", file.getName()); 

¿Cuál es la diferencia entre estos dos formas de concatenación, nunca usé el último sin embargo.

Saludos.

Respuesta

11

Ignoraría la advertencia (y la apagaré, si es posible). La concatenación no es tan ineficiente, porque los compiladores modernos la reemplazan con una implementación eficiente basada en StringBuilder (la verá si mira el bytecode del classfile).

El reemplazo sugerido no concaten secuencias, pero requiere un procesamiento adicional para analizar la plantilla y fusionarla con los parámetros.

Netbeans, eso es un mal consejo.

Esto es válido para Java 1.5+. Las versiones antiguas de Java (pueden) crean una gran cantidad de casos no utilizados String durante la concatenación ..

+3

Para desactivar la advertencia (en NetBeans 7.2.1): Preferencias -> Editor -> Sugerencias -> Registro -> Concatenación de cadenas en el registrador. La descripción dice: " No es eficiente en el rendimiento para concatenar cadenas en los mensajes del registrador. Es mejor usar un mensaje de plantilla con marcadores de posición que se reemplazan por valores concretos solo cuando el mensaje realmente se va a registrar". –

+0

Realmente te perdiste una de las principales ventajas, añadiré una respuesta ahora aunque sea tarde :) –

+3

Pero la advertencia es una ineficiencia debido a que la concatenación siempre se ejecuta en lugar de ejecutarla solo dependiendo del nivel de registro actual en el caso de usar el ['log (Level level, String msg, Object [] params)'] (https://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html # log-java.util.logging.Level-java.lang.String-java.lang.Object: A-) method. – Adam

4

Dado que las cadenas son inmutables en Java, al concatenar objetos String, en realidad crea un objeto completamente nuevo. Usar algo como la plantilla que sugiere Netbeans o StringBuilder le impide tener que crear todos esos objetos intermedios, lo que lleva tiempo y recursos.

+0

Excepto que los compiladores de Java modernos usarán un StringBuilder para usted, ese no es el motivo en este caso. –

11

La verdadera victoria aquí es que usted no tiene que hacer ninguna manipulación alguna (ya sea concatenación o una plantilla de expansión) del hilo, si el registrador está configurado para no iniciar sesión en el nivel INFO.

Es decir, el registrador puede decidir no hacer nada en absoluto sin tener que acercarse a ningún tipo de manipulación de cadenas.

1

Una plantilla significa exactamente eso, se supone que es una plantilla para una cadena, en lugar de una cadena en sí misma. La idea es que el bit {0} se sustituirá por el primer argumento que aparece después de él en la lista (file.getName()). Esto sigue el patrón del método Stringformat.

No he visto ninguna prueba de rendimiento para verificar si esto es más rápido o no. Como otras respuestas han señalado, dejarlo como está no será particularmente lento ya que el compilador usará StringBuilder en lugar de una cadena normal. Sin embargo, como señala @dty, creo que debería ser más rápido en el caso de que el nivel de registro esté configurado para que la declaración no se registre realmente, ya que no se requiere trabajo para construir la cadena para su salida. Además, dado que toda la cadena de la plantilla es un solo literal, el compilador lo agregará al conjunto de cadenas. Esto significa que todas las instancias de este particular String apuntan a la misma instancia real, por lo que si la declaración no se registra realmente, entonces ni siquiera tiene que asignar memoria para almacenar esta cadena, simplemente la busca, lo que debería ser más eficiente.

1

La advertencia que recibe de NetBeans le ofrece la justificación más corta para evitar la concatenación en la declaración de registro.

  1. Los mensajes de registro que no se van a enviar al registro no se generan cuando se utiliza el estilo de plantilla. Incluso puede optimizar el estilo un poco más evitando llamadas a métodos en la lista de argumentos.

Pero hay otras razones para elegir usar el estilo de plantilla para el mensaje de registro.

a. Evita la posible sobrecarga de concat. Como otros han señalado, este no es un gran problema con los javacs recientes.

b. Su código está mejor preparado para la internacionalización/localización. Mientras que usted puede pensar ... este código nunca necesitará ese nivel de preocupación ... es sorprendente qué tan lejos va el código después de que se haya escrito inicialmente.

16

El mensaje no se refiere al costo de la concatenación de cadenas en sí mismo. Las otras respuestas son absolutamente correctas cuando dicen que se usará un StringBuilder.

La razón principal para usar una plantilla de mensaje es porque el procesamiento solo se realiza cuando se muestra el nivel de registro.

Usemos estos dos ejemplos:

srcLogger.getLogger().log(Level.INFO,"UploadBean.doUpload completado [" + file.getName() + "]\n"); 
srcLogger.getLogger().log(Level.INFO, "UploadBean.doUpload completado [{0}]\n", file.getName()); 

Con información de depuración de nivel en: Ambos tienen que obtener el nombre de archivo del archivo, ambos tienen que actualizar la cadena, generar uno nuevo, mostrarlo.

Con nivel de depuración INFO apagado: La segunda respuesta pasa por el nombre del objeto File (que es una consulta simple), el método log() comprueba el nivel INFO y lo devuelve inmediatamente. ¡No se realiza el procesamiento String en absoluto!

Imaginemos ahora que, en lugar de un simple file.getName(), estábamos registrando un objeto más complejo, que en sí mismo necesitaba mucha concatenación de cadenas en el método toString(). Al registrar esos objetos directamente, no se realiza ninguno de esos procesos. toString() ni siquiera se llama a menos que se muestre el nivel de depuración.

Por lo tanto, la plantilla de mensaje no es más eficiente en el caso donde se muestra el registro, pero es enormemente más eficiente (particularmente en casos de registro no trivial) cuando el registro no se muestra. Uno de los objetivos del registro debe ser que, si el registro se desactiva, tenga el menor impacto posible en el rendimiento del sistema.

Cuestiones relacionadas