Чому ми оголошуємо лісоруби статичними фіналами?


131

Чому на Java чому найкраще застосовувати реєстрацію реєстратора static final?

private static final Logger S_LOGGER

Відповіді:


209
  • private- так що жоден інший клас не може викрасти ваш лісоруб
  • static - тож існує лише один екземпляр реєстратора в класі, що також уникає спроб серіалізації реєстраторів
  • final - не потрібно змінювати реєстратор протягом життя класу

Крім того, я вважаю за краще, logщоб ім’я було максимально простим, але описовим.

EDIT: Однак є цікавий виняток із цих правил:

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

на відміну від:

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

Колишній спосіб дозволяє використовувати однакове ім’я реєстратора (ім'я фактичного класу) у всіх класах у всій ієрархії спадкування. Тож якщо Barрозширення Foo, обидва ввійдуть до Barреєстратора. Деякі вважають це більш інтуїтивно зрозумілим.


36
якщо статичний і остаточний, то швидше LOG (верхній регістр)
zacheusz

39
@zacheusz , я знаю, в цьому справа. Деякі дотримуються конвенції про іменування Java релігійно (нічого поганого в цьому), але я вважаю за краще простіше писати і приємніше читати logім'я, а не розкидати код за допомогою LOG. Справа дев. командна угода.
Томаш Нуркевич

27
Зауважте, що не завжди рекомендується оголошувати реєстратори статичними і остаточними, див. Розділ slf4j.org/faq.html#declared_static та wiki.apache.org/commons/Logging/FrequentlyAskedQuestions Чи слід оголошувати посилання журналу статичними чи ні?
Меттью Фарвелл

6
@zacheusz Верхнє ім'я поля використовується для констант. Журнал не є постійним. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman

2
@zacheusz не всі статичні кінцеві атрибути повинні бути ВЕРХНІЙ: stackoverflow.com/questions/1417190 / ...
bsmk

15

Перевірте цю публікацію в блозі: Позбудьтесь статичних журналів Java . Ось як ви використовуєте slf4j з jcabi-log :

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

І ніколи більше не використовуйте цей статичний шум.


Цікава альтернатива і, безумовно, чистіше. Цікаво, як це масштаби порівняно з окремими реєстраторами класів.
Росс

12
Пишіть довше Logger .. (це, ...) кожного разу. Ні.
Михайло Боярський

Перший коментар у відповідному дописі на блозі вказує на злу сторону статичних методів :) Отже, використання приватного остаточного Logger - найкраща практика.
Бахадір Тасдемір,

5

staticозначає, що ви створюєте лише один реєстратор у класі, а не один реєстратор на примірник вашого класу. Взагалі, це саме те, що ти хочеш - оскільки лісоруби мають тенденцію змінюватися виключно залежно від класу.

finalозначає, що ви не збираєтесь змінювати значення loggerзмінної. Що вірно, оскільки ви майже завжди кидаєте всі повідомлення журналу (з одного класу) в один і той же реєстратор. Навіть у рідкісних випадках, коли клас може захотіти надсилати деякі повідомлення до іншого реєстратора, було б набагато зрозуміліше створити іншу змінну реєстратора (наприклад widgetDetailLogger), а не мутувати значення статичної змінної на льоту.


4

Коли ви хочете змінити значення поля?

Якщо ви ніколи не збираєтесь змінювати значення, завдяки тому, що фінал поля дає зрозуміти, що ви ніколи не змінюєте значення.


1
У багатьох-багатьох випадках це очевидно без додавання слова final, яке в цьому випадку стає своєрідним мотлохом.
Діма

2
@Dima: Ну , я до сих пір вдячний , що компілятор все одно буде видавати помилку , якщо я дійсно випадково спробувати змінити значення в таких випадках ...
Джон Скит

3

Зазвичай ви ініціалізуєте журнал реєстрації, використовуючи ім'я класу - це означає, що якби вони не були статичними, ви б закінчували кожен екземпляр класу, який має його примірник (високий слід пам'яті), але всі ці реєстратори мали б мають однакову конфігурацію і поводяться абсолютно однаково. Це причина за staticшматочком. Крім того, оскільки кожен Loggerініціалізується з назвою класу, щоб запобігти конфліктам з підкласами, ви заявляєте його, privateщоб він не міг успадковуватися. Це finalвідбувається з того, що ви зазвичай не змінюєте Loggerпід час виконання - так що після ініціалізації ви ніколи не "переконфігурували" його - у цьому випадку має сенс зробити остаточне, щоб ніхто не міг його змінити ( помилка чи інше). Звичайно, якщо ви збираєтесь використовувати aLoggerпо-іншому вам може знадобитися НЕ використовувати static final- але я б ризикну здогадатися, що 80% додатків використовуватимуть журнал, як пояснено вище.


3

Щоб відповісти на це запитання, ви мали б запитати себе, що таке "статичне" та "остаточне".

Для Logger, (я вважаю, що ви говорите про клас Log4J Logger), вам потрібна категорія на клас. Що повинно призвести до того, що ви призначаєте його лише один раз, і не потрібно більше одного екземпляра на клас. І, мабуть, немає причин піддавати об’єкт Logger одного класу іншому, то чому б не робити його приватним та слідувати деяким принципам ОО.

Також слід зазначити, що компілятор може скористатися цим. Так ваш код працює трохи краще :)


2

Тому що це, як правило, вид функціональності, яким можна ділитися у всіх примірниках ваших об'єктів. Немає особливого сенсу (90% часу) мати різний реєстратор для двох примірників одного класу.

Однак ви також можете побачити іноді класи реєстраторів, оголошені як одиночні кнопки, або навіть просто пропонувати статичні функції для реєстрації ваших речей.


2

Цей код є вразливим ,, але після Java7 ми можемо використовувати Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); замість статичного реєстратора.


This is code is vulnerableЧи можете ви уточнити, що ви трохи відповіли?
Дмитро

1

У більшості випадків ви не збираєтесь змінювати посилання і finalмодифікатор позначає його. Вам не потрібні окремі екземпляри для кожного екземпляра класу - так static. І насамперед це для продуктивності - це може бути добре оптимізовано (остаточне) та економить пам’ять (статична).


1

В ідеалі Logger має бути наступним чином до Java 7, щоб не надавати Sonar і надавати Код відповідності: приватний: ніколи не бути доступним за межами свого батьківського класу. Якщо іншому класу потрібно щось зареєструвати, він повинен створити власний реєстратор. статичний: не залежати від екземпляра класу (об’єкта). Під час реєстрації чогось, звичайно, у повідомленнях може бути надана контекстна інформація, але реєстратор повинен бути створений на рівні класу, щоб запобігти створенню реєстратора разом з кожним об'єктом і, отже, запобігання сліду високої пам'яті. остаточний: створюється один раз і лише один раз у класі.


0

На додаток до причин, наведених в інших відповідях, я натрапив на те, що якщо мій лісоруб не був ні статичним, ні остаточним:

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

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

у певних випадках (коли я використовував бібліотеку Gson), я отримав би виняток stackoverflow. Моя конкретна ситуація полягала в тому, щоб створити екземпляр класу, що містить нестатичний не остаточний реєстратор. Потім зателефонуйте до методу toJson, який викликав GsonBuilder:

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

0

Насправді статичні реєстратори можуть бути "шкідливими", оскільки вони повинні працювати в статичному контексті. При наявності динамічного середовища, наприклад. OSGi може допомогти використовувати нестатичні реєстратори. Оскільки деякі реалізації журналів здійснюють кешування журналів внутрішньо (AFAIK принаймні log4j), вплив на продуктивність може бути незначним.

Одним недоліком статичних реєстраторів є, наприклад. збирання сміття (коли клас використовується лише один раз, наприклад, під час ініціалізації журнал зберігається навколо).

Для отримання більш детальної інформації перевірте:

Дивитися також:


0

Згідно з інформацією, яку я прочитав з Інтернету про те, як зробити лісоруб статичним чи ні, найкращим методом є використання його відповідно до випадків використання.

Є два основні аргументи:

1) Коли ви робите статичну, вона не збирає сміття (використання пам'яті та продуктивність).

2) Якщо ви не робить його статичним, він створюється для кожного екземпляра класу (використання пам'яті)

Таким чином, коли ви створюєте реєстратор для одиночного, вам не потрібно робити його статичним. Тому що буде лише один екземпляр, таким чином, один реєстратор.

З іншого боку, якщо ви створюєте реєстратор для моделі або класу сутності, вам слід статично не створювати дублюються реєстратори.


-1

Вам все ще потрібен статичний реєстратор для внутрішніх статичних класів

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.