¿Por qué declaramos Loggers static static?

131

En Java, ¿por qué es una mejor práctica declarar un registrador static final?

private static final Logger S_LOGGER
usuario489041
fuente

Respuestas:

209
  • private- para que ninguna otra clase pueda secuestrar tu registrador
  • static - por lo que solo hay una instancia de registrador por clase, evitando también los intentos de serializar registradores
  • final - no es necesario cambiar el registrador durante la vida útil de la clase

Además, prefiero que el nombre logsea ​​lo más simple posible, pero descriptivo.

EDITAR: Sin embargo, hay una excepción interesante a estas reglas:

protected final Logger log = LoggerFactory.getLogger(getClass());

Opuesto a:

private static final Logger log = LoggerFactory.getLogger(Foo.class);

La primera forma le permite usar el mismo nombre de registrador (nombre de la clase real) en todas las clases en toda la jerarquía de herencia. Entonces, si se Barextiende Foo, ambos iniciarán sesión en el Barregistrador. Algunos lo encuentran más intuitivo.

Tomasz Nurkiewicz
fuente
36
si estático y final, entonces más bien LOG (mayúscula)
zacheusz
39
@zacheusz , lo sé, ese es el punto. Algunos siguen la convención de nomenclatura de Java religiosamente (no tiene nada de malo), pero prefiero un lognombre más fácil de escribir y más agradable de leer que dispersar el código LOG. Solo es cuestión de dev. acuerdo de equipo
Tomasz Nurkiewicz
27
Tenga en cuenta que ya no siempre se recomienda declarar los registradores como estáticos y finales, consulte slf4j.org/faq.html#declared_static y wiki.apache.org/commons/Logging/FreuallyAskedQuestions ¿Debo declarar las referencias de registro estáticas o no?
Matthew Farwell
66
@zacheusz El nombre del campo en mayúsculas se usa para constantes. El registrador no es constante. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman
2
@zacheusz no todos los atributos finales estáticos deben ser MAYÚSCULAS: stackoverflow.com/questions/1417190/…
bsmk
15

Consulte esta publicación de blog: Deshágase de los registradores estáticos de Java . Así es como usas slf4j con jcabi-log :

import com.jcabi.log.Logger;
class Foo {
  void save(File f) {
    Logger.info(this, "file %s saved successfully", f);
  }
}

Y nunca más uses ese ruido estático.

yegor256
fuente
Una alternativa interesante y definitivamente más limpia. Me pregunto cómo se compara esto con los registradores de clase individuales.
Ross
12
Escriba Logger más largo ... (esto, ...) cada vez. Nah
Mikhail Boyarsky
El primer comentario en la publicación de blog relacionada indica el lado malo de los métodos estáticos :) Entonces, supongo que usar el Final Logger privado es la mejor práctica.
Bahadir Tasdemir
5

staticsignifica que solo crea un registrador por clase, no un registrador por instancia de su clase. En general, esto es lo que desea, ya que los registradores tienden a variar únicamente según la clase.

finalsignifica que no vas a cambiar el valor de la loggervariable. Lo cual es cierto, ya que casi siempre arroja todos los mensajes de registro (de una clase) al mismo registrador. Incluso en las raras ocasiones en que una clase quiera enviar algunos mensajes a un registrador diferente, sería mucho más claro crear otra variable de registrador (por ejemplo widgetDetailLogger) en lugar de mutar el valor de una variable estática sobre la marcha.

Andrzej Doyle
fuente
4

¿Cuándo quieres cambiar el valor del campo?

Si nunca va a cambiar el valor, hacer que el campo sea final hace obvio que nunca cambiará el valor.

Jon Skeet
fuente
1
En muchos casos, es obvio sin agregar la palabra final, que en este caso se convierte en una especie de basura.
Dima
2
@Dima: Bueno, yo todavía estoy agradecido de que el compilador todavía generará un error si no accidentalmente a tratar de cambiar el valor en estos casos ...
Jon Skeet
3

Normalmente, inicializa el registrador para iniciar sesión utilizando el nombre de la clase, lo que significa que si no fuera estático, terminaría con cada instancia de la clase teniendo una instancia de él (huella de memoria alta), pero todos estos registradores lo harían comparte la misma configuración y se comporta exactamente igual. Esa es la razón detrás de la staticparte. Además, debido a que cada uno Loggerse inicializa con el nombre de la clase, para evitar conflictos con las subclases, usted lo declara privatepara que no se pueda heredar. Definal viene del punto en que normalmente no cambia Loggerdurante la ejecución, por lo que una vez inicializado nunca lo "reconfigura", en cuyo caso tiene sentido hacerlo final para asegurarse de que nadie pueda cambiarlo (por error o de otra manera). Por supuesto si vas a usar unLoggerde una manera diferente, es posible que NO necesite usar static final, pero me aventuraría a adivinar que el 80% de las aplicaciones usarían el registro como se explicó anteriormente.

Liv
fuente
3

Para responder a esa pregunta, debería haberse preguntado para qué sirven "estático" y "final".

Para un Logger, (supongo que habla de la clase Log4J Logger) desea una categoría por clase. Lo que debería llevar al hecho de que lo asigna solo una vez, y no hay necesidad de más de una instancia por clase. Y presumiblemente no hay razón para exponer el objeto Logger de una clase a otra, entonces, ¿por qué no hacerlo privado y seguir algunos Principios OO?

También debe tener en cuenta que el compilador puede aprovechar eso. Entonces su código funciona un poco mejor :)

Daniel Leschkowski
fuente
2

Porque ese suele ser el tipo de funcionalidad que se puede compartir en todas las instancias de sus objetos. No tiene mucho sentido (90% del tiempo) tener un registrador diferente para dos instancias de la misma clase.

Sin embargo, también puede ver a veces las clases de registrador declaradas como singletons o incluso simplemente ofreciendo funciones estáticas para registrar sus cosas.

Vincent Mimoun-Prat
fuente
2

Este código es vulnerable, pero, después de Java7, podemos usarlo en Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); lugar del registrador estático.

nkduqi
fuente
This is code is vulnerable¿Podría aclarar que responde un poco?
Dmitry Zagorulkin
1

En la mayoría de los casos, no va a cambiar la referencia y el finalmodificador lo marca. No necesita instancias separadas para cada instancia de clase, entonces static. Y, en primer lugar, esto es para el rendimiento : se puede optimizar (final) y ahorra memoria (estática).

zacheusz
fuente
1

Idealmente, Logger debería ser el siguiente hasta Java 7, para no dar Sonar y dar un Código de cumplimiento: privado: nunca estará accesible fuera de su clase padre. Si otra clase necesita registrar algo, debe crear una instancia de su propio registrador. static: no dependerá de una instancia de una clase (un objeto). Al registrar algo, por supuesto, se puede proporcionar información contextual en los mensajes, pero el registrador debe crearse a nivel de clase para evitar crear un registrador junto con cada objeto y, por lo tanto, evitar la huella de memoria alta. final: se creará una vez y solo una vez por clase.

Kratika Chaurasia
fuente
0

Además de las razones dadas en las otras respuestas, una cosa con la que me topé fue que si mi registrador no era estático ni final:

...
public Logger logger = LoggerFactory.getLogger(DataSummary.class);

public String toJson() {
  GsonBuilder gsonBuilder = new GsonBuilder();   
  return gsonBuilder.create().toJsonTree(this).toString();
}
...

en ciertos casos (cuando estaba usando la biblioteca Gson) obtendría una excepción stackoverflow. Mi situación específica fue crear una instancia de la clase que contiene el registrador no estático no final. Luego llame al método toJson que invocó a GsonBuilder:

...
DataSummary ds = new DataSummary(data);    
System.out.println(ds.toJson());
...
Pablo
fuente
0

En realidad, los registradores estáticos pueden ser "dañinos" ya que se supone que funcionan en un contexto estático. Al tener un entorno dinámico, por ejemplo. OSGi podría ayudar el uso de registradores no estáticos. Como algunas implementaciones de registro hacen un almacenamiento en caché de los registradores internamente (AFAIK al menos log4j), el impacto en el rendimiento puede ser insignificante.

Un inconveniente de los registradores estáticos es, por ejemplo. recolección de basura (cuando una clase se usa solo una vez, por ejemplo, durante la inicialización, el registrador se mantendrá).

Para más detalles consultar:

Ver también:

ViToni
fuente
0

Según la información que leí en Internet sobre cómo hacer que el registrador sea estático o no, la mejor práctica es usarlo de acuerdo con los casos de uso.

Hay dos argumentos principales:

1) Cuando lo hace estático, no se recolecta basura (uso de memoria y rendimiento).

2) Cuando no lo hace estático, se crea para cada instancia de clase (uso de memoria)

Por lo tanto, cuando crea un registrador para un singleton, no necesita hacerlo estático. Porque solo habrá una instancia, por lo tanto, un registrador.

Por otro lado, si está creando un registrador para un modelo o clase de entidad, debe hacerlo estático para no crear registradores duplicados.

Bahadir Tasdemir
fuente
-1

Todavía necesita un registrador estático para las clases estáticas internas.

Al Emu
fuente