Должен ли «статический финальный регистратор» быть объявлен в UPPER-CASE?

243

В Java статические конечные переменные являются константами, и существует соглашение, что они должны быть в верхнем регистре. Тем не менее, я видел, что большинство людей объявляют регистраторы в нижнем регистре, что является нарушением PMD .

например:

private static final Logger logger = Logger.getLogger(MyClass.class);

Просто поиск Google или SO для «статического окончательного регистратора» , и вы увидите это сам.

Должны ли мы использовать LOGGER вместо этого?

кендырь
источник
PMD или Checkstyle - это преждевременные наивные попытки повысить читабельность, но они приносят больше вреда, чем пользы. Наиболее читаемый стиль может меняться от случая к случаю в зависимости от контекста. Посмотрите на Guava или JDK src, они не следуют строгому шаблону стиля, но сделаны профессионалами, это неоспоримо. пример: DelegatedExecutorService @ docjar.com/html/api/java/util/concurrent/Executors.java.html
Даниэль Хари
У правил сонара ( rules.sonarsource.com/java/tag/convention/RSPEC-1312 ) также естьprivate static final Logger LOGGER = LoggerFactory.getLogger(Foo.class);
Кенстон Чой

Ответы:

306

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

private static final Logger logger = Logger.getLogger(MyClass.class);

private static final double MY_CONSTANT = 0.0;
crunchdog
источник
42
Статические конечные ссылки являются константами, если они неизменны. по этой логике у вас никогда не будет постоянных строк, потому что любая статическая конечная строка является ссылкой.
Джеффри Блатман
30
Но java.lang.String в любом случае является неизменяемым и особенным видом класса (см. String.intern (), документация о пуле Sring и т. Д.)
Александр Адамовский
3
неизменный означает, что состояние объекта не может измениться после строительства. см. мой пост ниже. регистраторы не обязательно являются изменяемыми.
Джеффри Блаттман
4
если кто-то все еще заботится об этой проблеме, пожалуйста, поделитесь идеями на github.com/checkstyle/checkstyle/issues/23 , чтобы определить , где требуется верхний регистр, а где нет.
Роман Иванов
2
@ Джич, я не думаю, что неизменность связана с тем, как меняется состояние, только с тем, что происходит. Кроме того, что пользователь? внешний пользователь запускает программу? Вы бы сделали различие между состоянием, изменяемым пользователем нажатием кнопки, и изменением состояния с помощью таймера, запускаемого через некоторый случайный интервал? (я так не думаю).
Джеффри Блатман
236

Чтобы повысить ценность ответа crunchdog, в Руководстве по стилю кодирования Java это указано в параграфе 3.3 «Имена полей».

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

  1. Все static finalпримитивные типы (Помните, что все поля интерфейса по своей природе static final).
  2. Все static finalссылочные типы объектов, за которыми никогда не следует " ." (точка).
  3. Все static finalмассивы, за которыми никогда не следует " [" (открывающая квадратная скобка).

Примеры:

MIN_VALUE, MAX_BUFFER_SIZE, OPTIONS_FILE_NAME

В соответствии с этим соглашением, loggerявляется static finalссылкой на объект , как указано в пункте 2, а потому , что это следует « .» каждый раз вы его используете, это не может рассматриваться как константа , и , следовательно , должны быть в нижнем регистре.

cbliard
источник
11
Лучшее определение, которое я видел для этого еще. Связанный документ, похоже, перенес вот обновление cs.bilgi.edu.tr/pages/standards_project/…
Роберт
15
Я не понимаю пункт 2. Что является примером типа объекта, за которым никогда не следует точка. Все типы объектов наследуются, Objectи вы можете вызвать метод, например, .equalsдля них.
Догбейн
6
Ты прав. И при просмотре некоторых Java-констант, таких как Boolean.TRUE, Boolean.FALSE, TimeUnit.MINUTES, String.CASE_INSENSITIVE_ORDER или Collections.EMPTY_LIST, за ними .также могут следовать .
cbliard
5
@RomanIvanov Я снова нашел его здесь: scribd.com/doc/15884743/Java-Coding-Style-by-Achut-Reddy, написанный Achut Reddy, последнее обновление 30 мая 2000 г.
cbliard
1
Я полагаю, что цель 2 состоит в том, чтобы обозначить, что только классы, которые должны сравниваться, считаются константами. Класс не предназначен для использования. Я всегда знаю, что передергивается, когда вижу SOME_CLASS.doStuff (). Это просто неаккуратное кодирование. Единственная проблема с этим заключается в общем случае константного объекта (String является общим примером), который предназначен только для сравнения, но чтобы избежать нулевых проверок, используется кодирование в стиле yoda, и, следовательно, equals () вызывается для константы. Я думаю, что сделал бы это одно предостережение для 2.
Робин
44

Из эффективной Java, 2-е изд.,

Единственное исключение из предыдущего правила касается «константных полей», имена которых должны состоять из одного или нескольких прописных слов, разделенных символом подчеркивания, например, VALUES или NEGATIVE_INFINITY. Постоянное поле - это статическое конечное поле, значение которого является неизменным . Если конечное статическое поле имеет примитивный тип или неизменный ссылочный тип (элемент 15), то оно является константным полем. Например, константы перечисления являются константными полями. Если статическое конечное поле имеет изменяемый ссылочный тип, оно все равно может быть константным полем, если указанный объект является неизменным.

В итоге, константа == static final, плюс, если это ссылка (по сравнению с простым типом), неизменность.

Глядя на регистратор slf4j, http://www.slf4j.org/api/org/slf4j/Logger.html

Это неизменно. С другой стороны, регистратор JUL изменчив. Регистратор log4j также изменчив. Таким образом, чтобы быть правильным, если вы используете log4j или JUL, это должен быть «logger», а если вы используете slf4j, это должен быть LOGGER.

Обратите внимание, что на приведенной выше странице javadocs slf4j есть пример, в котором они используют «logger», а не «LOGGER».

Это, конечно, только условные обозначения, а не правила. Если вы используете slf4j и хотите использовать «регистратор», потому что вы привыкли к этому из других платформ, или если его легче набирать, или для удобства чтения, продолжайте.

Джеффри Блаттман
источник
2
Исходя из этих рассуждений, тогда упрощенное определение checkstyle неуместно, верно?
Роберт
3
Я не знаю, проверьте правила стиля. если он просто настаивает на том, что любой статический финал должен быть в верхнем регистре, тогда да, это неправильно.
Джеффри Блатман
5
Как именно Logger интерфейс неизменен ? Только final class(как Stringили Integer) может гарантировать неизменность. Даже если вы не можете найти изменчивую реализацию SLF4J Logger, никто не может помешать вам написать ее самостоятельно.
Costi Ciudatu
Потому что методы в интерфейсе не допускают мутации по своей сути. Вы правы, хотя могли бы реализовать интерфейс, чтобы иметь изменяемые побочные эффекты.
Джеффри Блатман
Проверяйте правила стиля недостаточно зрелыми, чтобы обеспечить читабельность. Читаемость не может быть достигнута с помощью шаблонов стиля, читаемость может отличаться от случая к случаю в зависимости от контекста. Посмотрите код JDK, он не соответствует ни одному шаблону стиля и сделан профессионалами, который что-то показывает.
Даниэль Хари
37

Мне нравится, что Google это делает ( стиль Google Java )

Каждая константа является статическим конечным полем, но не все статические конечные поля являются константами. Прежде чем выбрать постоянный регистр, подумайте, действительно ли поле ощущается как константа. Например, если какое-либо наблюдаемое состояние этого экземпляра может измениться, оно почти наверняка не является константой. Простого намерения никогда не мутировать объект обычно недостаточно.

Примеры:

// Constants
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
static final Joiner COMMA_JOINER = Joiner.on(',');  // because Joiner is immutable
static final SomeMutableType[] EMPTY_ARRAY = {};
enum SomeEnum { ENUM_CONSTANT }

// Not constants
static String nonFinal = "non-final";
final String nonStatic = "non-static";
static final Set<String> mutableCollection = new HashSet<String>();
static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};
mateuscb
источник
6
Я думаю, что первое предложение резюмирует это кратко: «Каждая константа является статическим конечным полем, но не все статические конечные поля являются константами». Легко использовать механическое мышление и просто иметь каждое статическое конечное поле в верхнем регистре (и я занимался этим до сих пор), но это упущение тонкости языка.
аяхуаска
Согласно этой цитате, все сводится к тому, что поле «действительно ощущается» как константа. Мы инженеры, а не психиатры.
Джеффри Блатман
«Подумайте, действительно ли это похоже на константу». Чьи-то чувства действительно не должны входить в сферу инжиниринга.
Джеффри Блаттман
Тогда в коде private static final Logger logger = Logger.getLogger(Finalizer.class.getName());
Гуавы
10

Если вы используете автоматизированный инструмент для проверки ваших стандартов кодирования, и он нарушает указанные стандарты, то его или стандарты должны быть исправлены. Если вы используете внешний стандарт, исправьте код.

Соглашение в Sun Java прописно для открытых статических констант. Очевидно, что регистратор не является константой, но представляет изменяемую вещь (иначе не было бы смысла вызывать методы для него в надежде, что что-то случится); не существует определенного стандарта для непостоянных конечных полей.

Пит Киркхэм
источник
10
Почему вы говорите, что регистратор не является постоянным? Это кажется постоянным действительно. Запись в журнал является побочным эффектом вызова его методов, но не изменяет его наблюдаемое состояние. Я что-то пропустил?
KLE
Проверьте API. У него есть пара методов добавления / получения. Но вы все равно ошибочны. Ведение журнала можно наблюдать (иначе какой смысл).
Том Хотин - tackline
3
Если бы это был StringBuilder, а не логгер, то, возможно, он был бы более очевидно непостоянным. Даже для регистраторов такие методы, как Logger.setLevel (), видимо видоизменяют получателя. Обычно верхний регистр предназначен для тех констант, которые языки рассматривают как константы и будут встроены.
Пит Киркхем
5
Регистратор не является константой, так как это ссылка на объект. Константы - это значения, которые нельзя изменить. Ссылка на объект является окончательной (поэтому ссылка на нее не может быть изменена, например, заменена чем-то другим или установлена ​​на нуль), но сам объект может.
Спойк
1
@JeffreyBlattman Я не согласен с тем, что все окончательные ссылки должны быть в верхнем регистре, но вы можете принять любые стандарты кодирования, которые вам нравятся. Я сожалею, что вы находите разницу между «изменяемым объектом» и «объектом, который представляет изменяемый объект»; Одним из примеров может быть номер вашего заднего счета, который сам по себе не меняется, но используется для доступа к переменному балансу. Посмотрите на разницу между означающим и значимым и для получения более подробной информации, или ознакомьтесь с монадой Лейбница о том, как неизменная вещь может представлять изменчивость.
Пит Киркхам
7

Если вы воспользуетесь этим, вы можете обнаружить, что в некоторых случаях регистраторы не определяются как статические окончательные. Добавьте к этому быстрое копирование и вставку, и это может объяснить это.

Мы используем LOGGER во всем нашем коде, и это соответствует нашему соглашению об именах (и наш CheckStyle доволен этим).


Мы даже идем дальше, пользуясь строгим соглашением об именах в Eclipse. Мы создаем новый класс с шаблоном кода:

    // private static final Logger LOGGER = Logger.getLogger(${enclosing_type}.class);

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

Затем в коде мы используем шаблоны кода, которые ожидают присутствия этого регистратора. Пример с шаблоном try-catch:

    try {
      ${cursor} or some other template
    } catch (Exception t) {
      LOGGER.error("${methodName} ${method parameters}", t);
    }

У нас есть еще несколько шаблонов, которые его используют.

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

KLE
источник
5
Поймать Throwable - плохая практика, если вы не войдете и не сбросите его. Помните об ошибках: OutOfMemeoryError и т. Д. Исключение событий не так безопасно, чтобы его можно было перехватить и обработать самостоятельно в многопоточных приложениях.
m_vitaly
2
Синтаксис Eclipse: Logger.getLogger ($ {enclosing_type} .class);
Dogbane
@fahdshariff Спасибо за точный синтаксис. Я обновил свой ответ.
KLE
Если «строгие соглашения» CheckStyle или PMD помогают, то почему в источниках Guava и JDK ЛЮБОЙ не применен общий стиль? Например, в их источнике много полно встроенных блоков, где это необходимо. Удобочитаемость зависит от контекста, поэтому использование строгих соглашений о стилях для всего разрушает контекстные решения и снижает удобочитаемость.
Даниэль Хари
6

Лично я думаю, что это выглядит действительно большим в верхнем регистре. Более того, поскольку это класс, который не имеет прямого отношения к поведению класса, я не вижу большой проблемы в использовании loggerвместо LOGGER. Но если вы собираетесь быть строго педантичным, то используйте LOGGER.

Жоао Силва
источник
4

Не забывайте, что PMD будет уважать комментарий с

// NOPMD

в этом. Это заставит PMD пропустить строку из своих проверок, это позволит вам выбрать любой стиль, который вы хотите.

Fortyrunner
источник
6
Или не используйте PMD, они всегда неправильны, и ваш код совершенен
IAdapter,
1
Если вам всегда нужно исключать проверку каждый раз, тогда проверка не имеет смысла.
Keiki
Не могу согласиться больше - однако ... полезно знать комментарий об исключении
Fortyrunner
3

Обычно константы в верхнем регистре.

Регистраторы, однако, не должны быть статичными, а должны искать каждый «новый» содержащий класс при использовании фасада slf4j. Это позволяет избежать некоторых неприятных проблем с загрузчиком классов, в частности, веб-контейнеров, а также позволяет каркасу ведения журналов выполнять специальные действия в зависимости от контекста вызова.

Турбьерн Равн Андерсен
источник
2

Я предпочитаю «регистратор», то есть строчные буквы. Причина не в том, что это константа или не константа (изменяемая или неизменная). Если бы мы использовали это рассуждение, нам пришлось бы переименовать переменную, если мы изменим каркас журналирования (или если каркас изменяет изменчивость логгеров).

Для меня важнее другие причины.

  1. Регистратор является теневым объектом в классе и не должен быть очень заметным, поскольку он не реализует основную логику. Если мы используем «LOGGER», это привлекает внимание кода, который привлекает слишком много внимания.

  2. Иногда регистраторы объявляются на уровне экземпляра (т. Е. Не являются статичными) и даже внедряются как зависимости. Я не хотел бы менять свой код, если я решил изменить способ получения регистратора. Стабильность кода относительно это (гипотетическое во многих случаях) изменение - еще одна причина, по которой я предпочитаю строчные буквы.

fml2
источник
1

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

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

Кстати: я предпочитаю "LOGGER" ;-)

Kutzi
источник