Pourquoi déclarons-nous les Loggers statiques finaux?

132

En Java, pourquoi est-il recommandé de déclarer un enregistreur static final?

private static final Logger S_LOGGER
user489041
la source

Réponses:

209
  • private- pour qu'aucune autre classe ne puisse détourner votre enregistreur
  • static - il n'y a donc qu'une seule instance d'enregistreur par classe, évitant également les tentatives de sérialisation des enregistreurs
  • final - pas besoin de changer l'enregistreur pendant la durée de vie de la classe

De plus, je préfère que le nom logsoit aussi simple que possible, mais descriptif.

EDIT: Cependant, il existe une exception intéressante à ces règles:

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

par opposition à:

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

La première méthode vous permet d'utiliser le même nom d'enregistreur (nom de la classe réelle) dans toutes les classes de la hiérarchie d'héritage. Donc, si Bars'étend Foo, les deux se connecteront à l' Barenregistreur. Certains le trouvent plus intuitif.

Tomasz Nurkiewicz
la source
36
si statique et final alors plutôt LOG (majuscule)
zacheusz
39
@zacheusz , je sais, c'est le but. Certains suivent religieusement la convention de nommage Java (rien de mal à cela), mais je préfère un nom plus facile à écrire et plus agréable à lire logplutôt que de disperser le code avec LOG. Juste une question de développement. accord d'équipe.
Tomasz Nurkiewicz
27
Veuillez noter qu'il n'est plus toujours recommandé de déclarer les enregistreurs comme statiques et définitifs, voir slf4j.org/faq.html#declared_static et wiki.apache.org/commons/Logging/FrequentAskedQuestions section Dois-je déclarer les références de journal statiques ou non?
Matthew Farwell
6
@zacheusz Le nom de champ en majuscules est utilisé pour les constantes. Logger n'est pas constant. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman
2
@zacheusz tous les attributs finaux statiques ne doivent pas être en MAJUSCULE: stackoverflow.com/questions/1417190/…
bsmk
15

Consultez ce billet de blog: Débarrassez-vous des enregistreurs statiques Java . Voici comment vous utilisez slf4j avec jcabi-log :

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

Et n'utilisez plus jamais ce bruit statique.

yegor256
la source
Une alternative intéressante et définitivement plus propre. Je me demande comment cela évolue par rapport aux enregistreurs de classe individuels.
Ross
12
Écrivez plus de Logger .. (ceci, ...) à chaque fois. Non.
Mikhail Boyarsky
Le premier commentaire dans le billet de blog associé indique le mauvais côté des méthodes statiques :) Donc, utiliser Private Final Logger est la meilleure pratique, je suppose.
Bahadir Tasdemir le
5

staticsignifie que vous ne créez qu'un seul enregistreur par classe, pas un enregistreur par instance de votre classe. En général, c'est ce que vous voulez - car les enregistreurs ont tendance à varier uniquement en fonction de la classe.

finalsignifie que vous n'allez pas changer la valeur de la loggervariable. Ce qui est vrai, puisque vous lancez presque toujours tous les messages de journal (d'une classe) au même enregistreur. Même dans les rares occasions où une classe pourrait vouloir envoyer des messages à un autre enregistreur, il serait beaucoup plus clair de créer une autre variable de journalisation (par exemple widgetDetailLogger) plutôt que de muter la valeur d'une variable statique à la volée.

Andrzej Doyle
la source
4

Quand voudriez-vous changer la valeur du champ?

Si vous ne modifiez jamais la valeur, le fait de rendre le champ définitif indique clairement que vous ne changerez jamais la valeur.

Jon Skeet
la source
1
Dans de nombreux cas, il est évident sans ajouter le mot final, ce qui dans ce cas devient une sorte d'ordure.
Dima
2
@Dima: Eh bien , je suis toujours reconnaissant que le compilateur sera toujours jeter une erreur si je n'essaie accidentellement de changer la valeur dans ces cas ...
Jon Skeet
3

Normalement, vous initialisez l'enregistreur pour qu'il enregistre en utilisant le nom de la classe - ce qui signifie que s'ils n'étaient pas statiques, vous vous retrouveriez avec chaque instance de la classe en ayant une instance (empreinte mémoire élevée), mais tous ces enregistreurs partagent la même configuration et se comportent exactement de la même manière. C'est la raison derrière le staticbit. De plus, parce que chacun Loggerest initialisé avec le nom de la classe, pour éviter les conflits avec les sous-classes, vous le déclarez privateafin qu'il ne puisse pas être hérité. Le finalvient du point que vous normalement ne modifiez pas le Loggercours de l'exécution - une fois que vous initialisés jamais « reconfiguré » - dans ce cas , il est logique de le rendre définitif pour assurer que personne ne peut changer (par erreur ou autre). Bien sûr, si vous allez utiliser unLoggerd'une manière différente, vous n'aurez peut-être PAS besoin de l'utiliser static final- mais je me risquerais à penser que 80% des applications utiliseraient la journalisation comme expliqué ci-dessus.

Liv
la source
3

Pour répondre à cette question, vous auriez dû vous demander à quoi servent les termes «statique» et «final».

Pour un enregistreur, (je suppose que vous parlez de la classe Log4J Logger), vous voulez une catégorie par classe. Ce qui devrait conduire au fait que vous ne l'attribuez qu'une seule fois et qu'il n'y a pas besoin de plus d'une instance par classe. Et il n'y a probablement aucune raison d'exposer l'objet Logger d'une classe à une autre, alors pourquoi ne pas le rendre privé et suivre quelques principes OO.

Notez également que le compilateur est capable d'en tirer profit. Donc, votre code fonctionne un peu mieux :)

Daniel Leschkowski
la source
2

Parce que c'est généralement le type de fonctionnalité qui peut être partagée entre toutes les instances de vos objets. Cela n'a pas beaucoup de sens (90% du temps) d'avoir un enregistreur différent pour deux instances de la même classe.

Cependant, vous pouvez également voir parfois des classes de journalisation déclarées comme des singletons ou même simplement proposer des fonctions statiques pour enregistrer vos données.

Vincent Mimoun-Prat
la source
2

Ce code est vulnérable , mais, après Java7, nous pouvons utiliser à la Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); place d'un enregistreur statique.

nkduqi
la source
This is code is vulnerablePourriez-vous clarifier votre réponse un peu?
Dmitry Zagorulkin
1

Dans la plupart des cas, vous n'allez pas modifier la référence et le finalmodificateur la marque. Vous n'avez pas besoin d'instances distinctes pour chaque instance de classe - donc static. Et tout d'abord, c'est pour la performance - il peut être bien optimisé (final) et économise de la mémoire (statique).

Zacheusz
la source
1

Idéalement, Logger devrait être comme suit jusqu'à Java 7, pour ne pas donner de Sonar et donner un code conforme: private: ne jamais être accessible en dehors de sa classe parente. Si une autre classe a besoin de consigner quelque chose, elle doit instancier son propre enregistreur. statique: ne pas être dépendant d'une instance d'une classe (un objet). Lors de la journalisation de quelque chose, des informations contextuelles peuvent bien sûr être fournies dans les messages, mais l'enregistreur doit être créé au niveau de la classe pour éviter de créer un enregistreur avec chaque objet et ainsi empêcher l'empreinte mémoire élevée. final: être créé une et une seule fois par classe.

Kratika Chaurasia
la source
0

En plus des raisons données dans les autres réponses, une chose que j'ai rencontrée était que si mon enregistreur n'était ni statique ni définitif:

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

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

dans certains cas (lorsque j'utilisais la bibliothèque Gson), j'obtiendrais une exception stackoverflow. Ma situation spécifique était d'instancier la classe contenant le logger non statique non final. Appelez ensuite la méthode toJson qui a appelé GsonBuilder:

...
DataSummary ds = new DataSummary(data);    
System.out.println(ds.toJson());
...
Paul
la source
0

En fait, les enregistreurs statiques peuvent être «nuisibles» car ils sont censés fonctionner dans un contexte statique. Lorsque vous avez un environnement dynamique, par exemple. OSGi, il peut être utile d'utiliser des enregistreurs non statiques. Comme certaines implémentations de journalisation font une mise en cache des enregistreurs en interne (AFAIK au moins log4j), l'impact sur les performances peut être négligeable.

Un inconvénient des enregistreurs statiques est par exemple. garbage collection (lorsqu'une classe n'est utilisée qu'une seule fois, par exemple lors de l'initialisation, l'enregistreur sera toujours conservé).

Pour plus de détails, consultez:

Voir également:

ViToni
la source
0

Selon les informations que j'ai lues sur Internet pour rendre l'enregistreur statique ou non, la meilleure pratique consiste à l'utiliser en fonction des cas d'utilisation.

Il y a deux arguments principaux:

1) Lorsque vous le rendez statique, il n'est pas ramassé (utilisation de la mémoire et performances).

2) Lorsque vous ne le rendez pas statique, il est créé pour chaque instance de classe (utilisation de la mémoire)

Ainsi, lorsque vous créez un enregistreur pour un singleton, vous n'avez pas besoin de le rendre statique. Parce qu'il n'y aura qu'une seule instance donc un enregistreur.

D'autre part, si vous créez un enregistreur pour un modèle ou une classe d'entité, vous devez le rendre statique pour ne pas créer d'enregistreurs dupliqués.

Bahadir Tasdemir
la source
-1

Vous avez toujours besoin d'un enregistreur statique pour les classes statiques internes

Al Emu
la source