Почему мы объявляем Logger static final?

132

Почему в Java лучше всего объявлять регистратор static final?

private static final Logger S_LOGGER
user489041
источник

Ответы:

209
  • private- чтобы никакой другой класс не мог захватить ваш регистратор
  • static - поэтому существует только один экземпляр регистратора на класс, что также позволяет избежать попыток сериализации регистраторов
  • final - нет необходимости менять логгер на протяжении жизни класса

Кроме того, я предпочитаю, logчтобы имя было как можно более простым, но информативным.

РЕДАКТИРОВАТЬ: Однако из этих правил есть интересное исключение:

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. Просто вопрос разработчика. командное соглашение.
Tomasz Nurkiewicz
27
Обратите внимание, что больше не рекомендуется объявлять регистраторы как статические и окончательные, см. Slf4j.org/faq.html#declared_static и раздел wiki.apache.org/commons/Logging/FrequentAskedQuestions Должен ли я объявлять ссылки журнала статическими или нет?
Мэтью Фаруэлл,
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);
  }
}

И никогда больше не используйте этот статический шум.

yegor256
источник
Интересная альтернатива и определенно более чистая. Интересно, как это масштабируется по сравнению с индивидуальными регистраторами классов.
Росс
12
Пишите дольше Регистратора .. (этого, ...) каждый раз. Неа.
Михаил Боярский
Первый комментарий в соответствующем сообщении в блоге указывает на плохую сторону статических методов :) Так что использование private final Logger - лучшая практика, я думаю.
Бахадир Тасдемир,
5

staticозначает, что вы создаете только один регистратор для каждого класса, а не один регистратор для каждого экземпляра вашего класса. Как правило, это именно то, что вам нужно, поскольку регистраторы, как правило, различаются исключительно в зависимости от класса.

finalозначает, что вы не собираетесь изменять значение loggerпеременной. Это правда, поскольку вы почти всегда отправляете все сообщения журнала (из одного класса) в один и тот же регистратор. Даже в тех редких случаях, когда классу может потребоваться отправить некоторые сообщения другому регистратору, было бы гораздо проще создать другую переменную регистратора (например widgetDetailLogger), чем изменять значение статической переменной на лету.

Анджей Дойл
источник
4

Когда вы хотите изменить значение поля?

Если вы никогда не собираетесь изменять значение, сделав поле final, станет очевидным, что вы никогда не измените значение.

Джон Скит
источник
1
Во многих-многих случаях это очевидно без добавления слова final, которое в данном случае становится своего рода мусором.
Дима
2
@Dima: Ну , я до сих пор благодарен , что компилятор все равно будет выдавать ошибку , если я действительно случайно попытаться изменить значение в таких случаях ...
Джон Скит
3

Обычно вы инициализируете регистратор для ведения журнала с использованием имени класса - это означает, что если бы они не были статическими, вы бы получили бы каждый экземпляр класса, имеющий его экземпляр (большой объем памяти), но все эти регистраторы будут использовать одну и ту же конфигурацию и вести себя одинаково. Это причина staticбиты. Кроме того, поскольку каждый Loggerинициализируется именем класса, чтобы предотвратить конфликты с подклассами, вы объявляете его, privateчтобы он не мог быть унаследован. Это finalпроисходит из-за того, что вы обычно не меняете Loggerво время выполнения - поэтому после инициализации вы никогда не «повторно настраиваете» его - в этом случае имеет смысл сделать его окончательным, чтобы никто не мог его изменить ( ошибка или иначе). Конечно, если вы собираетесь использоватьLoggerпо-другому, возможно, вам НЕ нужно использовать static final- но я рискну предположить, что 80% приложений будут использовать ведение журнала, как описано выше.

Liv
источник
3

Чтобы ответить на этот вопрос, вы должны были спросить себя, для чего нужны «статика» и «финал».

Для регистратора (я полагаю, вы говорите о классе Log4J Logger) вам нужна категория для каждого класса. Это должно привести к тому, что вы назначаете его только один раз, и нет необходимости в более чем одном экземпляре для каждого класса. И, по-видимому, нет причин открывать объект Logger одного класса другому, так почему бы не сделать его частным и не следовать некоторым OO-принципам.

Также вы должны отметить, что компилятор может воспользоваться этим. Так что ваш код работает немного лучше :)

Даниэль Лешковски
источник
2

Потому что обычно это тот вид функциональности, который можно использовать для всех экземпляров ваших объектов. Не имеет большого смысла (в 90% случаев) иметь разные средства ведения журнала для двух экземпляров одного и того же класса.

Однако вы также можете иногда видеть классы регистраторов, объявленные как одиночные или просто предлагающие статические функции для регистрации ваших данных.

Винсент Мимун-Прат
источник
2

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

nkduqi
источник
This is code is vulnerableНе могли бы вы немного уточнить ответ?
Дмитрий
1

В большинстве случаев вы не собираетесь изменять ссылку, и finalмодификатор отмечает ее. Вам не нужны отдельные экземпляры для каждого экземпляра класса - поэтому static. И в первую очередь это для производительности - ее можно красиво оптимизировать (окончательно) и сэкономить память (статика).

zacheusz
источник
1

В идеале до Java 7 Logger должен быть таким, чтобы не давать Sonar и давать совместимый код: private: никогда не быть доступным за пределами своего родительского класса. Если другому классу нужно что-то регистрировать, он должен создать свой собственный регистратор. статический: не зависеть от экземпляра класса (объекта). При регистрации чего-либо контекстная информация, конечно, может быть предоставлена ​​в сообщениях, но регистратор должен быть создан на уровне класса, чтобы предотвратить создание регистратора вместе с каждым объектом и, следовательно, предотвратить использование высокой памяти. final: создаваться один раз и только один раз для каждого класса.

Kratika Chaurasia
источник
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), влияние на производительность может быть незначительным.

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

Для получения более подробной информации проверьте:

Смотрите также:

ViToni
источник
0

Согласно информации, которую я прочитал из Интернета о том, чтобы сделать регистратор статическим или нет, лучше всего использовать его в соответствии с вариантами использования.

Есть два основных аргумента:

1) Когда вы делаете его статическим, это не сборщик мусора (использование памяти и производительность).

2) Когда вы не делаете его статическим, он создается для каждого экземпляра класса (использование памяти)

Таким образом, когда вы создаете регистратор для синглтона, вам не нужно делать его статическим. Потому что будет только один экземпляр, то есть один регистратор.

С другой стороны, если вы создаете регистратор для модели или класса сущности, вы должны сделать его статическим, чтобы не создавать дублированные регистраторы.

Бахадир Тасдемир
источник
-1

Вам все еще нужен статический регистратор для внутренних статических классов

Аль Эму
источник