Warum ist es in Java empfehlenswert, einen Logger zu deklarieren static final
?
private static final Logger S_LOGGER
Warum ist es in Java empfehlenswert, einen Logger zu deklarieren static final
?
private static final Logger S_LOGGER
Antworten:
private
- damit keine andere Klasse Ihren Logger entführen kannstatic
- Es gibt also nur eine Logger-Instanz pro Klasse, wodurch auch Versuche vermieden werden, Logger zu serialisierenfinal
- Der Logger muss während der gesamten Lebensdauer der Klasse nicht geändert werdenAußerdem bevorzuge ich, dass der Name log
so einfach wie möglich und dennoch beschreibend ist.
EDIT: Es gibt jedoch eine interessante Ausnahme zu diesen Regeln:
protected final Logger log = LoggerFactory.getLogger(getClass());
im Gegensatz zu:
private static final Logger log = LoggerFactory.getLogger(Foo.class);
Auf die erstere Weise können Sie in allen Klassen der Vererbungshierarchie denselben Loggernamen (Namen der tatsächlichen Klasse) verwenden. Wenn also Bar
verlängert Foo
, werden beide beim Bar
Logger protokolliert . Einige finden es intuitiver.
log
Namen angenehmer zu lesen, als den Code mit zu streuen LOG
. Nur eine Frage der Entwicklung. Teamvereinbarung.
Überprüfen Sie diesen Blog-Beitrag: Befreien Sie sich von Java Static Loggers . So verwenden Sie slf4j mit jcabi-log :
import com.jcabi.log.Logger;
class Foo {
void save(File f) {
Logger.info(this, "file %s saved successfully", f);
}
}
Und verwenden Sie dieses statische Rauschen nie mehr.
static
bedeutet, dass Sie nur einen Logger pro Klasse erstellen, nicht einen Logger pro Instanz Ihrer Klasse. Im Allgemeinen ist dies das, was Sie möchten - da die Logger in der Regel nur je nach Klasse variieren.
final
bedeutet, dass Sie den Wert der logger
Variablen nicht ändern werden. Dies ist der Fall, da Sie fast immer alle Protokollnachrichten (von einer Klasse) an denselben Protokollierer senden. Selbst in den seltenen Fällen, in denen eine Klasse einige Nachrichten an einen anderen Logger senden möchte, ist es viel klarer, eine andere Logger-Variable (z. B. widgetDetailLogger
) zu erstellen, als den Wert einer statischen Variablen im laufenden Betrieb zu ändern.
Wann möchten Sie den Wert des Feldes ändern?
Wenn Sie den Wert niemals ändern, wird durch das Festlegen des Felds deutlich, dass Sie den Wert niemals ändern werden.
Normalerweise initialisieren Sie den Logger so, dass er unter Verwendung des Klassennamens protokolliert wird. Wenn diese nicht statisch wären, würde jede Instanz der Klasse eine Instanz davon haben (hoher Speicherbedarf), aber alle diese Logger würden dies tun teilen die gleiche Konfiguration und verhalten sich genauso. Das ist der Grund für das static
bisschen. Da Logger
Konflikte jeweils mit dem Klassennamen initialisiert werden, deklarieren Sie private
sie , um Konflikte mit Unterklassen zu vermeiden, damit sie nicht vererbt werden können. Das final
kommt von dem Punkt, an dem Sie das normalerweise Logger
während der Ausführung nicht ändern - also haben Sie es nach der Initialisierung nie "neu konfiguriert" - in diesem Fall ist es sinnvoll, es endgültig zu machen, um sicherzustellen, dass niemand es ändern kann (durch Fehler oder auf andere Weise). Natürlich, wenn Sie a verwenden wollenLogger
Auf eine andere Art und Weise müssen Sie möglicherweise NICHT verwenden static final
- aber ich wage zu vermuten, dass 80% der Apps die Protokollierung wie oben erläutert verwenden würden.
Um diese Frage zu beantworten, sollten Sie sich gefragt haben, wofür "statisch" und "endgültig" sind.
Für einen Logger (ich nehme an, Sie sprechen über die Log4J Logger-Klasse) möchten Sie eine Kategorie pro Klasse. Dies sollte dazu führen, dass Sie es nur einmal zuweisen und nicht mehr als eine Instanz pro Klasse erforderlich ist. Und vermutlich gibt es keinen Grund, das Logger-Objekt einer Klasse einer anderen auszusetzen. Warum also nicht privat machen und einigen OO-Prinzipien folgen?
Beachten Sie auch, dass der Compiler davon profitieren kann. Ihr Code ist also etwas besser :)
Denn dies ist normalerweise die Art von Funktionalität, die für alle Instanzen Ihrer Objekte gemeinsam genutzt werden kann. Es ist nicht sehr sinnvoll (in 90% der Fälle), für zwei Instanzen derselben Klasse einen anderen Logger zu haben.
Manchmal sehen Sie jedoch auch Logger-Klassen, die als Singletons deklariert sind oder einfach statische Funktionen zum Protokollieren Ihrer Daten anbieten.
Dieser Code ist anfällig, aber nach Java7 können wir Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
anstelle des statischen Loggers verwenden.
This is code is vulnerable
Könnten Sie klarstellen, dass Sie ein bisschen antworten?
In den meisten Fällen werden Sie die Referenz nicht ändern, und der final
Modifikator markiert sie. Sie benötigen nicht für jede Klasseninstanz separate Instanzen static
. Und dies dient in erster Linie der Leistung - es kann gut optimiert werden (endgültig) und spart Speicher (statisch).
Im Idealfall sollte Logger bis Java 7 wie folgt sein, um kein Sonar und einen kompatiblen Code anzugeben: privat: Niemals außerhalb der übergeordneten Klasse zugänglich sein. Wenn eine andere Klasse etwas protokollieren muss, sollte sie ihren eigenen Logger instanziieren. statisch: nicht abhängig von einer Instanz einer Klasse (einem Objekt). Wenn Sie etwas protokollieren, können natürlich Kontextinformationen in den Nachrichten bereitgestellt werden, aber der Logger sollte auf Klassenebene erstellt werden, um zu verhindern, dass zusammen mit jedem Objekt ein Logger erstellt wird und somit ein hoher Speicherbedarf vermieden wird. final: einmal und nur einmal pro Klasse erstellt werden.
Zusätzlich zu den in den anderen Antworten angegebenen Gründen stieß ich auf Folgendes, wenn mein Logger weder statisch noch endgültig war:
...
public Logger logger = LoggerFactory.getLogger(DataSummary.class);
public String toJson() {
GsonBuilder gsonBuilder = new GsonBuilder();
return gsonBuilder.create().toJsonTree(this).toString();
}
...
In bestimmten Fällen (wenn ich die Gson-Bibliothek verwendete) wurde eine Stackoverflow-Ausnahme angezeigt. Meine spezielle Situation bestand darin, die Klasse zu instanziieren, die den nicht statischen nicht endgültigen Logger enthält. Rufen Sie dann die toJson-Methode auf, die GsonBuilder aufgerufen hat:
...
DataSummary ds = new DataSummary(data);
System.out.println(ds.toJson());
...
Tatsächlich können statische Logger "schädlich" sein, da sie in einem statischen Kontext arbeiten sollen. In einer dynamischen Umgebung, z. OSGi kann es hilfreich sein, nicht statische Logger zu verwenden. Da einige Protokollierungsimplementierungen das interne Zwischenspeichern von Protokollierern durchführen (AFAIK mindestens log4j), können die Auswirkungen auf die Leistung vernachlässigbar sein.
Ein Nachteil von statischen Loggern ist z. Speicherbereinigung (wenn eine Klasse nur einmal verwendet wird, z. B. während der Initialisierung, bleibt der Logger weiterhin in der Nähe).
Weitere Details finden Sie unter:
Siehe auch:
Nach den Informationen, die ich aus dem Internet darüber gelesen habe, ob der Logger statisch ist oder nicht, ist es die beste Vorgehensweise, ihn entsprechend den Anwendungsfällen zu verwenden.
Es gibt zwei Hauptargumente:
1) Wenn Sie es statisch machen, wird kein Müll gesammelt (Speichernutzung und Leistung).
2) Wenn Sie es nicht statisch machen, wird es für jede Klasseninstanz erstellt (Speichernutzung)
Wenn Sie also einen Logger für einen Singleton erstellen, müssen Sie ihn nicht statisch machen. Weil es nur eine Instanz gibt, also einen Logger.
Wenn Sie dagegen einen Logger für ein Modell oder eine Entitätsklasse erstellen, sollten Sie es statisch machen, keine doppelten Logger zu erstellen.