Neden Loggers'ı statik final ilan ediyoruz?


132

Java'da, neden bir günlükçü bildirmek en iyi uygulamadır static final?

private static final Logger S_LOGGER

Yanıtlar:


209
  • private- böylece başka hiçbir sınıf kaydedicinizi ele geçiremez
  • static - böylece sınıf başına yalnızca bir günlük kaydedici örneği vardır ve ayrıca günlükleri serileştirme girişimlerini de önler
  • final - sınıfın ömrü boyunca kaydediciyi değiştirmeye gerek yok

Ayrıca, adın logolabildiğince basit ama açıklayıcı olmasını tercih ederim .

DÜZENLEME: Ancak bu kuralların ilginç bir istisnası var:

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

aksine:

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

İlk yöntem, miras hiyerarşisi boyunca tüm sınıflarda aynı günlükçü adını (gerçek sınıfın adı) kullanmanıza izin verir. Yani eğer Bargenişlerse Foo, her ikisi de Barlogger'a kaydedilir. Bazıları bunu daha sezgisel buluyor.


36
Statik ve son ise daha çok LOG (büyük harf)
zacheusz

39
@zacheusz , biliyorum, mesele bu. Bazıları Java adlandırma kuralını dini olarak takip ediyor (bunda yanlış bir şey yok), ancak logkodu dağıtmak yerine yazmayı daha kolay ve daha keyifli bir ad okumayı tercih ediyorum LOG. Sadece bir geliştirme meselesi. takım anlaşması.
Tomasz Nurkiewicz

27
Kaydedicilerin statik ve nihai olarak bildirilmesinin artık her zaman tavsiye edilmediğini lütfen unutmayın, bkz. Slf4j.org/faq.html#declared_static ve wiki.apache.org/commons/Logging/FrequentlyAskedQuestions bölümü Günlük referanslarını statik olarak beyan etmeli miyim?
Matthew Farwell

6
@zacheusz Büyük harfli alan adı sabitler için kullanılır. Logger sabit değildir. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman

2
@zacheusz tüm statik son öznitelikler BÜYÜK HARF olmamalıdır: stackoverflow.com/questions/1417190/…
bsmk

15

Şu blog gönderisine bakın: Java Static Logger'lardan Kurtulun . Jcabi-log ile slf4j'yi şu şekilde kullanıyorsunuz :

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

Ve bu statik gürültüyü bir daha asla kullanmayın.


İlginç bir alternatif ve kesinlikle daha temiz. Bireysel sınıf kaydedicilerle karşılaştırıldığında bunun nasıl ölçeklendiğini merak ediyorum.
Ross

12
Her seferinde daha uzun Logger .. (bu, ...) yazın. Hayır.
Mikhail Boyarsky

İlgili blog gönderisindeki ilk yorum, statik yöntemlerin kötü yönünü gösteriyor :) Bu nedenle özel final Logger kullanmak sanırım en iyi uygulamadır.
Bahadır Taşdemir

5

staticYalnızca değil, sınıf başına başına bir logger bir Logger oluşturmak demek olduğunu örneğinin sınıfının. Genel olarak, istediğiniz şey budur - çünkü kaydediciler yalnızca sınıfa göre değişme eğilimindedir.

finalloggerdeğişkenin değerini değiştirmeyeceğiniz anlamına gelir . Bu doğrudur, çünkü neredeyse her zaman tüm günlük mesajlarını (bir sınıftan) aynı kaydediciye atarsınız. Bir sınıfın farklı bir kaydediciye bazı mesajlar göndermek isteyebileceği ender durumlarda bile, widgetDetailLoggerstatik bir değişkenin değerini anında değiştirmekten ziyade başka bir kaydedici değişkeni (örneğin ) oluşturmak çok daha açık olacaktır .


4

Alanın değerini ne zaman değiştirmek istersiniz?

Değeri asla değiştirmeyecekseniz, alanı final yapmak , değeri asla değiştirmeyeceğinizi açıkça ortaya koyar.


1
Pek çok durumda, final kelimesini eklemeden de açıktır, ki bu durum bir tür hurda haline gelir.
Dima

2
@Dima: Eh ben hala eğer derleyici hala bir hata atmak edeceğini minnettarım do ... yanlışlıkla bu durumlarda değerini değiştirmek için denemek
Jon Skeet

3

Normalde, sınıf adını kullanarak günlüğe kaydediciyi başlatırsınız - bu, statik olmasalar, sınıfın her bir örneğinin bir örneğine sahip olacağı anlamına gelir (yüksek bellek ayak izi), ancak tüm bu kaydediciler aynı yapılandırmayı paylaşır ve tamamen aynı şekilde davranır. staticBiraz arkasındaki sebep bu . Ayrıca Logger, her biri sınıf adıyla başlatıldığından, alt sınıflarla çakışmaları önlemek privateiçin, miras alınamayacak şekilde beyan edersiniz . finalNormalde değişmez o noktadan itibaren gelir Loggerile (ki bu durumda kimsenin değiştirebilirsiniz sağlamak için nihai hale getirmek için mantıklı - bu yüzden zaman onu "yeniden yapılandırılmış" asla başlatıldı - yürütülürken hata veya başka türlü). Tabii ki kullanacaksanızLoggerfarklı bir şekilde ihtiyaç duyabileceğiniz DEĞİL kullanımına static final- ancak yukarıda açıklandığı gibi uygulamaların% 80 günlüğü kullanmak istiyorsunuz tahmin girişim olacaktır.


3

Bu soruyu cevaplamak için, kendinize "durağan" ve "son" un ne anlama geldiğini sormanız gerekir.

Bir Logger için (Log4J Logger sınıfı hakkında konuştuğunuzu varsayıyorum) sınıf başına bir kategori istiyorsunuz. Bu, onu yalnızca bir kez atamanıza yol açmalıdır ve sınıf başına birden fazla örneğe gerek yoktur. Ve muhtemelen bir sınıfın Logger nesnesini diğerine ifşa etmek için bir neden yoktur, öyleyse neden onu özel yapıp bazı OO İlkelerini takip etmiyorsunuz?

Ayrıca, derleyicinin bundan faydalanabileceğini de unutmamalısınız. Yani kodunuz biraz daha iyi performans gösteriyor :)


2

Çünkü bu, genellikle nesnelerinizin tüm örnekleri arasında paylaşılabilen bir tür işlevselliktir. Aynı sınıfın iki örneği için farklı bir kaydediciye sahip olmak çok mantıklı değildir (zamanın% 90'ı).

Bununla birlikte, bazen günlükçü sınıflarının tekli olarak bildirildiğini veya hatta öğelerinizi kaydetmek için statik işlevler sunduğunu da görebilirsiniz.


2

Bu kod savunmasızdır , ancak Java7'den sonra Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); statik günlükleyici yerine kullanabiliriz .


This is code is vulnerableBiraz cevap verir misin?
Dmitry Zagorulkin

1

Çoğu durumda referansı finaldeğiştirmezsiniz ve değiştirici onu işaretler. Her sınıf örneği için ayrı örneklere ihtiyacınız yoktur - yani static. Ve her şeyden önce bu performans içindir - güzel bir şekilde optimize edilebilir (son) ve hafızadan (statik) tasarruf sağlar.


1

İdeal olarak Logger, Sonar vermemek ve Uyumlu Kod vermek için Java 7'ye kadar aşağıdaki şekilde olmalıdır: özel: asla ana sınıfının dışında erişilemez. Başka bir sınıfın bir şeyi günlüğe kaydetmesi gerekiyorsa, kendi günlükçüsünü başlatmalıdır. statik: bir sınıfın (bir nesnenin) bir örneğine bağlı olmayın. Bir şeyi günlüğe kaydederken, içeriğe dayalı bilgiler elbette mesajlarda sağlanabilir, ancak kaydedici, her bir nesneyle birlikte bir kaydedici oluşturmayı ve dolayısıyla Yüksek Bellek ayak izini önlemeyi önlemek için sınıf düzeyinde oluşturulmalıdır. final: sınıf başına bir kez ve yalnızca bir kez oluşturulur.


0

Diğer cevaplarda verilen nedenlere ek olarak, karşılaştığım bir şey, kaydedicimin ne statik ne de nihai olmamasıydı:

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

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

belirli durumlarda (Gson kitaplığını kullanırken) stackoverflow istisnası alırdım. Benim özel durumum, statik olmayan son günlük kaydediciyi içeren sınıfı somutlaştırmaktı. Sonra GsonBuilder'ı çağıran toJson yöntemini çağırın:

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

0

Aslında statik kaydediciler, statik bir bağlamda çalışması gerektiğinden "zararlı" olabilir. Dinamik bir ortama sahipken örn. OSGi, statik olmayan kaydedicilerin kullanılmasına yardımcı olabilir. Bazı günlük uygulamaları dahili olarak kaydedicilerin önbelleğe alınmasını sağladığından (AFAIK en azından log4j) performans etkisi ihmal edilebilir.

Statik kaydedicilerin bir dezavantajı, örn. çöp toplama (bir sınıf yalnızca bir kez kullanıldığında, örneğin başlatma sırasında kaydedici hala ortalıkta tutulacaktır).

Daha fazla ayrıntı için kontrol edin:

Ayrıca bakınız:


0

Logger'ı statik hale getirip getirmeme konusunda internetten okuduğum bilgilere göre, en iyi uygulama onu kullanım durumlarına göre kullanmaktır.

İki ana argüman var:

1) Statik hale getirdiğinizde, çöp toplanmaz (bellek kullanımı ve performans).

2) Statik yapmadığınızda, her sınıf örneği için oluşturulur (bellek kullanımı)

Bu nedenle, bir singleton için bir kaydedici oluştururken, onu statik hale getirmenize gerek yoktur. Çünkü sadece bir örnek ve dolayısıyla bir kaydedici olacaktır.

Öte yandan, bir model veya varlık sınıfı için bir kaydedici oluşturuyorsanız, yinelenen günlükler oluşturmamak için statik hale getirmelisiniz.


-1

İç statik sınıflar için hala statik günlüğe ihtiyacınız var

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.