En Java, pourquoi est-il préférable de déclarer un enregistreur static final
?
private static final Logger S_LOGGER
private
- afin qu'aucune autre classe ne puisse détourner votre enregistreurstatic
- il n'y a donc qu'une seule instance de consignateur par classe, évitant également les tentatives de sérialisation des enregistreursfinal
- pas besoin de changer l'enregistreur pendant la durée de vie de la classeDe plus, je préfère que le nom log
soit 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 méthode précédente vous permet d’utiliser le même nom de journal (nom de la classe réelle) dans toutes les classes de la hiérarchie de l’héritage. Donc, si Bar
étend Foo
, les deux se connecteront à Bar
enregistreur. Certains le trouvent plus intuitif.
Consultez cet article de blog: Débarrassez-vous de Java Enregistreurs statiques . 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 ce bruit statique.
static
signifie que vous ne créez qu'un seul enregistreur par classe, pas un enregistreur par instance de votre classe. Généralement, c'est ce que vous voulez - les enregistreurs ont tendance à varier uniquement en fonction de la classe.
final
signifie que vous n'allez pas modifier la valeur de la variable logger
. Ce qui est vrai, puisque vous envoyez presque toujours tous les messages de journal (d'une classe) au même enregistreur. Même dans les rares cas où une classe voudrait envoyer des messages à un autre enregistreur, il serait beaucoup plus clair de créer une autre variable d’enregistreur (par exemple, widgetDetailLogger
) plutôt que de muter la valeur d’une variable statique de la même manière. voler.
Pour répondre à cette question, vous auriez dû vous demander à quoi servent "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 vous amener à ne l'attribuer qu'une seule fois et à ne pas avoir besoin de plus d'une instance par classe. Et vraisemblablement, il n'y a aucune raison d'exposer l'objet Logger d'une classe à une autre, alors pourquoi ne pas le rendre privé et suivre certains principes OO.
Aussi, vous devriez noter que le compilateur est capable de tirer profit de cela. Donc, votre code fonctionne un peu mieux :)
Quand voudriez-vous changer la valeur du champ?
Si vous ne modifiez jamais la valeur, rendre le champ final rend évident que vous ne modifierez jamais la valeur.
Normalement, vous enregistrez le journal avec le nom de la classe. Autrement dit, si elles n’étaient pas statiques, chaque instance de la classe en aurait une instance (encombrement mémoire élevé), mais tous ces enregistreurs partager la même configuration et se comporter exactement la même chose. C'est la raison derrière le bit static
. De plus, étant donné que chaque Logger
est initialisé avec le nom de la classe, pour éviter les conflits avec les sous-classes, vous le déclarez private
afin qu'il ne puisse pas être hérité. Le final
provient du point où vous ne changez normalement pas le Logger
pendant l'exécution - de sorte qu'une fois initialisé, vous ne le "reconfigurez" jamais - auquel cas il est logique de rendez-le final pour vous assurer que personne ne peut le changer (par erreur ou autrement). Bien sûr, si vous allez utiliser un Logger
d'une manière différente, vous aurez peut-être besoin de ET PAS pour utiliser static final
- mais je me risquerais à penser que 80% des applications utiliseraient la journalisation comme expliqué ci-dessus.
Parce que c'est généralement le type de fonctionnalité qui peut être partagé sur toutes les instances de vos objets. Cela n'a pas beaucoup de sens (90% du temps) d'avoir un logger différent pour deux instances de la même classe.
Cependant, vous pouvez aussi voir parfois des classes de consignateurs déclarées comme des singletons ou même offrant simplement des fonctions statiques pour enregistrer vos données.
Dans la plupart des cas, vous n'allez pas changer la référence et le modificateur final
la marque. Vous n'avez pas besoin d'instances séparées pour chaque instance de classe - donc static
. Et tout d’abord, c’est pour la performance - il peut être bien optimisé (final) et économiser de la mémoire (statique).
Ce code est vulnérable , mais, après Java7, nous pouvons utiliser Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
à la place de l'enregistreur statique.
Idéalement, Logger devrait être comme suit jusqu'à Java 7, pour ne donner aucun sonar et donner un code conforme: private: ne soit jamais 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 dépendre d'une instance de classe (un objet). Lors de la journalisation, des informations contextuelles peuvent bien sûr être fournies dans les messages, mais l'enregistreur doit être créé au niveau de la classe pour empêcher la création d'un enregistreur. avec chaque objet, évitant ainsi l’empreinte mémoire élevée. final: être créé une et une seule fois par classe.
En plus des raisons données dans les autres réponses, je me suis heurté à une chose 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 l'enregistreur non statique non final. Ensuite, appelez la méthode toJson qui a appelé GsonBuilder:
...
DataSummary ds = new DataSummary(data);
System.out.println(ds.toJson());
...