Dlaczego deklarujemy statyczną wersję Loggerów jako ostateczną?


136

Dlaczego w Javie najlepiej jest zadeklarować program rejestrujący static final?

private static final Logger S_LOGGER

Odpowiedzi:


213
  • private- aby żadna inna klasa nie mogła przejąć twojego loggera
  • static - więc istnieje tylko jedna instancja programu rejestrującego na klasę, co pozwala również uniknąć prób serializacji rejestratorów
  • final - nie ma potrzeby zmiany loggera w czasie trwania klasy

Ponadto wolę, logaby nazwa była jak najprostsza, a jednocześnie opisowa.

EDYCJA: Istnieje jednak ciekawy wyjątek od tych zasad:

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

w przeciwieństwie do:

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

Pierwszy sposób umożliwia użycie tej samej nazwy programu rejestrującego (nazwy rzeczywistej klasy) we wszystkich klasach w hierarchii dziedziczenia. Więc jeśli Barrozszerzy Foo, oba będą logować się do Barrejestratora. Niektórzy uważają to za bardziej intuicyjne.


38
jeśli statyczny i ostateczny, to raczej LOG (wielkie litery)
zacheusz.

41
@zacheusz , wiem, o to chodzi. Niektórzy religijnie przestrzegają konwencji nazewnictwa Java (nie ma w tym nic złego), ale ja wolę łatwiejsze do napisania i przyjemniejsze do odczytania lognazwy niż rozpraszanie kodu LOG. Tylko kwestia dev. umowa zespołowa.
Tomasz Nurkiewicz

27
Należy pamiętać, że nie zawsze jest zalecane deklarowanie rejestratorów jako statycznych i ostatecznych, zobacz sekcję slf4j.org/faq.html#declared_static i wiki.apache.org/commons/Logging/FrequentlyAskedQuestions Czy powinienem zadeklarować odniesienia do dziennika jako statyczne?
Matthew Farwell

6
@zacheusz Wielkimi literami nazwa pola jest używana dla stałych. Rejestrator nie jest stały. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman

2
@zacheusz nie wszystkie statyczne atrybuty końcowe powinny być
WIELKIMI LITERAMI

15

Sprawdź ten wpis na blogu: Pozbądź się Java Static Loggers . Oto jak używasz slf4j z jcabi-log :

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

I nigdy więcej nie używaj tego statycznego szumu.


1
Ciekawa alternatywa i zdecydowanie czystsza. Zastanawiam się, jak to się skaluje w porównaniu z rejestratorami poszczególnych klas.
Ross

13
Napisz dłuższy Logger… (this…) za każdym razem. Nie.
Michaił Bojarski

Pierwszy komentarz w powiązanym wpisie na blogu wskazuje na złą stronę metod statycznych :) Tak więc myślę, że używanie prywatnego końcowego Loggera jest najlepszą praktyką.
Bahadir Tasdemir

5

staticoznacza, że ​​tworzysz tylko jeden program rejestrujący na klasę, a nie jeden program rejestrujący na instancję swojej klasy. Generalnie tego właśnie chcesz - ponieważ rejestratory zwykle różnią się wyłącznie w zależności od klasy.

finaloznacza, że ​​nie zamierzasz zmieniać wartości loggerzmiennej. Co jest prawdą, ponieważ prawie zawsze wysyłasz wszystkie komunikaty dziennika (z jednej klasy) do tego samego programu rejestrującego. Nawet w rzadkich przypadkach, gdy klasa może chcieć wysłać jakieś komunikaty do innego programu rejestrującego, znacznie bardziej przejrzyste byłoby utworzenie innej zmiennej rejestrującej (np. widgetDetailLogger) Zamiast modyfikowania wartości zmiennej statycznej w locie.


4

Kiedy chciałbyś zmienić wartość pola?

Jeśli nigdy nie zamierzasz zmieniać wartości, ostateczna wersja pola sprawia, że oczywiste jest , że nigdy nie zmienisz wartości.


1
W wielu, wielu przypadkach JEST to oczywiste bez dodawania słowa final, co w tym przypadku staje się rodzajem śmieci.
Dima

2
@Dima: Więc nadal jestem wdzięczny, że kompilator będzie nadal wygeneruje błąd, jeśli nie przypadkowo próbować zmienić wartość w tych sprawach ...
Jon Skeet

3

Zwykle inicjujesz rejestrator do rejestrowania przy użyciu nazwy klasy - co oznacza, że ​​gdyby nie były statyczne, skończyłoby się na tym, że każda instancja klasy miałaby swoją instancję (duży ślad pamięci), ale wszystkie te rejestratory mają tę samą konfigurację i zachowują się dokładnie tak samo. To jest powód tego staticbitu. Ponieważ każda Loggerz nich jest inicjalizowana nazwą klasy, aby zapobiec konfliktom z podklasami, deklarujesz ją, privateaby nie mogła być dziedziczona. finalPochodzi od miejsca, które normalnie nie zmienić Loggerw trakcie realizacji - tak raz zainicjowany nigdy „rekonfiguracji” to - w tym przypadku ma to sens, aby końcowy, aby zapewnić nikt nie może go zmienić (przez błąd lub w inny sposób). Oczywiście, jeśli masz zamiar użyćLoggerw inny sposób, może być konieczne NIE do użytku static final- ale Zaryzykowałbym domyślić 80% aplikacji użyłby rejestrowanie jak wyjaśniono powyżej.


3

Aby odpowiedzieć na to pytanie, powinieneś zadać sobie pytanie, do czego służą „statyczne” i „ostateczne”.

Dla Loggera (zakładam, że mówisz o klasie Log4J Logger) chcesz mieć kategorię na klasę. Co powinno prowadzić do tego, że przypisujesz ją tylko raz i nie ma potrzeby posiadania więcej niż jednej instancji na klasę. I przypuszczalnie nie ma powodu, aby ujawniać obiekt Logger jednej klasy drugiej, więc dlaczego nie uczynić go prywatnym i przestrzegać pewnych zasad OO.

Należy również pamiętać, że kompilator może to wykorzystać. Twój kod działa więc trochę lepiej :)


2

Ponieważ zazwyczaj jest to rodzaj funkcji, która może być współdzielona we wszystkich instancjach twoich obiektów. Nie ma większego sensu (w 90% przypadków) posiadanie innego rejestratora dla dwóch instancji tej samej klasy.

Jednak czasami możesz zobaczyć klasy rejestratorów zadeklarowane jako pojedyncze lub nawet oferujące funkcje statyczne do rejestrowania twoich rzeczy.


2

Ten kod jest podatny na ataki ,, ale po Javie7 możemy użyć Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); zamiast statycznego rejestratora.


This is code is vulnerableCzy mógłbyś trochę wyjaśnić swoją odpowiedź?
Dmitry Zagorulkin

1

W większości przypadków nie będziesz zmieniać odniesienia, a finalmodyfikator je oznaczy. Nie potrzebujesz osobnych instancji dla każdej instancji klasy - więc static. A przede wszystkim ze względu na wydajność - można go ładnie zoptymalizować (finalnie) i oszczędzać pamięć (statycznie).


1

Idealnie byłoby, gdyby Logger był następujący aż do Java 7, aby nie dawać sonaru i dawać Zgodny kod: prywatny: nigdy nie będzie dostępny poza swoją klasą nadrzędną. Jeśli inna klasa musi coś zarejestrować, powinna utworzyć własną instancję rejestrującą. statyczny: nie zależy od instancji klasy (obiektu). Podczas rejestrowania czegoś, informacje kontekstowe mogą być oczywiście dostarczane w komunikatach, ale rejestrator powinien być utworzony na poziomie klasy, aby zapobiec tworzeniu programu rejestrującego wraz z każdym obiektem, a tym samym zapobiec zużyciu dużej ilości pamięci. finał: być utworzony raz i tylko raz na zajęcia.


1

Zgodnie z informacjami, które przeczytałem z Internetu, na temat ustawiania loggera w stanie statycznym lub nie, najlepszą praktyką jest używanie go zgodnie z przypadkami użycia.

Istnieją dwa główne argumenty:

1) Po ustawieniu go jako statycznego nie jest on zbierany jako śmieci (użycie pamięci i wydajność).

2) Jeśli nie ustawisz go statycznie, jest tworzony dla każdej instancji klasy (użycie pamięci)

Tak więc, kiedy tworzysz rejestrator dla singletona, nie musisz ustawiać go statycznie. Ponieważ będzie tylko jedna instancja, a więc jeden rejestrator.

Z drugiej strony, jeśli tworzysz program rejestrujący dla modelu lub klasy encji, powinieneś ustawić statyczne, aby nie tworzyć zduplikowanych rejestratorów.


0

Oprócz powodów podanych w innych odpowiedziach jedną rzecz, na którą natknąłem się, było to, że jeśli mój rejestrator nie był ani statyczny, ani ostateczny:

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

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

w niektórych przypadkach (gdy korzystałem z biblioteki Gson) otrzymywałem wyjątek stackoverflow. Moja konkretna sytuacja polegała na utworzeniu instancji klasy zawierającej niestatyczny, niekońcowy rejestrator. Następnie wywołaj metodę toJson, która wywołała GsonBuilder:

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

0

W rzeczywistości statyczne rejestratory mogą być „szkodliwe”, ponieważ powinny działać w kontekście statycznym. Mając dynamiczne środowisko np. OSGi może pomóc użycie niestatycznych rejestratorów. Ponieważ niektóre implementacje rejestrowania wykonują wewnętrzne buforowanie rejestratorów (AFAIK co najmniej log4j), wpływ na wydajność może być pomijalny.

Wadą rejestratorów statycznych jest np. wyrzucanie elementów bezużytecznych (gdy klasa jest używana tylko raz, np. podczas inicjalizacji, rejestrator będzie nadal dostępny).

Aby uzyskać więcej informacji, sprawdź:

Zobacz też:


-1

Nadal potrzebujesz statycznego rejestratora dla wewnętrznych klas statycznych

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.