Чи повинен бути оголошений "статичний кінцевий реєстратор" у верхньому випадку?


243

У Java статичні кінцеві змінні є константами, і умовою є те, що вони повинні бути великими. Однак я бачив, що більшість людей заявляють реєстратори в малих регістрах, що вважається порушенням PMD .

наприклад:

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

Просто шукайте в Google або SO "статичний остаточний реєстратор", і ви переконаєтесь у цьому самі.

Чи слід замість цього використовувати LOGGER?


ПМД або 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

Посилання реєстратора не є постійною, а кінцевою посиланням, і НЕ повинно бути великим. Постійна VALUE повинна бути великою літерою.

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

private static final double MY_CONSTANT = 0.0;

42
статичні кінцеві посилання є константами, якщо вони незмінні. за цією логікою ви ніколи не матимете постійних рядків, оскільки будь-яка статична кінцева рядок є посиланням.
Джефрі Блатман

30
Але java.lang.String є непорушним і особливий вид класу в будь-якому випадку (див String.intern (), документацію про Sring басейну і т.д.)
Олександр Adamowski

3
незмінне означає, що стан об'єкта не може змінитися після будівництва. дивіться мою публікацію нижче. лісоруби не обов'язково змінюються.
Джефрі Блатман

4
якщо хтось все ще переймається цією проблемою, будь ласка, поділіться ідеями на github.com/checkstyle/checkstyle/isissue/23 , щоб визначити , де потрібні великі регістри , а де ні.
Роман Іванов

2
@Jeach Я не думаю, що незмінність стосується того, як змінюється стан, лише це робить. більше того, що користувач? зовнішній користувач, який запускає програму? Ви б зробили різницю між тим, що стан змінюється користувачем, який натискає кнопку, і його змінює таймер, що запускається через деякий випадковий інтервал? (я не думаю, що так).
Джеффрі Блатман

236

Щоб додати більше значення відповіді крихти, в Посібнику стилю кодування 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, а тому , що це слід « .» кожен раз ви його використовуєте, це не може розглядатися як константа , і , отже , повинні бути в нижньому регістрі.


11
Найкраще визначення, яке я бачив для цього ще. Зв'язаний документ, здається, перемістився ось оновлення cs.bilgi.edu.tr/pages/standards_project/…
robert

15
Я не розумію точки 2. Що таке приклад типу об'єкта, за яким ніколи не йде точка. Усі типи об'єктів успадковуються Objectі ви можете викликати такий метод, як .equalsна них.
собачка

6
Ти правий. І дивлячись на деякі константи Java, такі як Boolean.TRUE, Boolean.FALSE, TimeUnit.MINUTES, String.CASE_INSENSITIVE_ORDER або Collections.EMPTY_LIST, вони також можуть супроводжуватися ..
кбліард

5
@RomanIvanov Я його знову знайшов тут: scribd.com/doc/15884743/Java-Coding-Style-by-Achut-Reddy, написаний Achut Reddy, остання зміна 30 травня 2000 р.
cbliard

1
Я вважаю, що мета 2 - визначити, що константами вважаються лише класи, які мають порівнюватися. Клас не призначений для "використання". Мені завжди відомо, що я бачу SOME_CLASS.doStuff (). Це просто нечітке кодування. Єдина проблема з цим полягає в загальному випадку постійного об'єкта (String є загальним прикладом), який призначений лише для порівняння, але щоб уникнути нульових перевірок, використовується кодування стилю йода і, таким чином, дорівнює константі (). Я думаю, що я зробив би це одне застереження до 2.
Робін

44

З ефективної java, 2-е видання,

Єдиний виняток із попереднього правила стосується "постійних полів", назви яких повинні складатися з одного або декількох великих речей, розділених символом підкреслення, наприклад, VALUES або NEGATIVE_INFINITY. Постійне поле - статичне кінцеве поле, значення якого незмінне . Якщо статичне кінцеве поле має примітивний тип або незмінний тип відліку (Пункт 15), то це постійне поле. Наприклад, константи перерахунків - це постійні поля. Якщо статичне кінцеве поле має змінний опорний тип, воно все одно може бути постійним полем, якщо посилається об'єкт є незмінним.

Підсумовуючи, константа == статичний фінал, плюс якщо це посилання (проти простого типу), незмінність.

Дивлячись на реєстратор slf4j, http://www.slf4j.org/api/org/slf4j/Logger.html

Це незмінне. З іншого боку, реєстратор JUL є змінним. Журнал log4j також може змінюватися. Отже, щоб бути правильним, якщо ви використовуєте log4j або JUL, він повинен бути "реєстратором", а якщо ви використовуєте slf4j, він повинен бути LOGGER.

Зауважте, що сторінка slf4j javadocs, пов'язана вище, має приклад, коли вони використовують "реєстратор", а не "ЛОГЕР".

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


2
Виходячи з цього міркування, тоді спрощене визначення контрольного стилю є невідповідним, правда?
Роберт

3
я не знаю правил перевірки стилю. якщо просто наполягати, що будь-який статичний фінал повинен бути великим, то так, це неправильно.
Джефрі Блатман

5
Наскільки саме Logger інтерфейс незмінний ? Тільки final class(як Stringабо Integer) може гарантувати незмінність. Навіть якщо ви не зможете знайти жодної змінної реалізації SLF4J Logger, ніхто не може перешкодити вам написати один.
Costi Ciudatu

Тому що методи в інтерфейсі не дозволяють мутації по суті. Ви маєте рацію, хоч могли б реалізувати інтерфейс, щоб мати мутаційні побічні ефекти.
Джефрі Блатман

Правила перевірки стилю НЕ ПОДАЄТЬСЯ, щоб чітко читати. Читання не може бути досягнуто за допомогою шаблону стилю, читабельність може відрізнятися від конкретного випадку залежно від контексту. Дивіться код JDK, він не відповідає жодному шаблону стилів, зробленому професіоналами, який щось показує.
Даніель Харі

37

Мені подобається взяти на себе Google ( стиль Java 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"};

6
Я думаю, що перше речення підсумовує це коротко: "Кожна константа є статичним кінцевим полем, але не всі статичні кінцеві поля є константами". Використовувати механічне мислення просто і просто мати кожне статичне остаточне поле у ​​верхньому регістрі (і я це робив дотепер), але це упустити тонкощі мови.
аяуаска

Згідно з цією цитатою, вона зводиться до того, якщо поле "справді відчуває себе" як константа. Ми інженери, а не психіатри.
Джефрі Блатман

"Подумайте ... чи справді це відчуває себе постійним". Чиїсь почуття дійсно не повинні входити в інженерну сферу.
Джефрі Блатман

Потім у коді private static final Logger logger = Logger.getLogger(Finalizer.class.getName());
Гуави

10

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

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


10
Чому ти кажеш, що лісоруб не є постійним? Це здається справді постійним. Журнал, що виробляється, є побічним ефектом виклику його методів, але не змінювати його стан спостереження. Я щось пропустив?
KLE

Перевірте API. У нього є пара методів додавання / отримання. Але ви міркування все одно помилкові. Ведення журналів спостерігається (інакше в чому сенс).
Том Хотін - тайклін

3
Якби це був StringBuilder, а не лісоруб, тоді, можливо, це було б більш очевидно непостійним. Навіть для реєстраторів такі методи, як Logger.setLevel (), вимкнено мутують приймач. Зазвичай великими літерами є ті константи, які мови розглядають як константи і будуть вбудованими.
Піт Кіркхем,

5
Реєстратор не є постійною, оскільки це посилання на об'єкт. Константи - це значення, які неможливо змінити. Посилання на об'єкт є остаточним (тому посилання на нього неможливо змінити, наприклад, замінити його чимось іншим або встановити на нуль), але сам об'єкт може.
Спойк

1
@JeffreyBlattman Я не згоден з тим, що всі остаточні посилання повинні бути великими літерами, але ви можете прийняти будь-які стандарти кодування, які вам подобаються. Мені шкода, що ви бачите різницю між "об'єктом, що змінюється", і "об'єктом, який представляє змінену річ", що плутає; одним із прикладів може бути номер вашого зворотного рахунку, який сам по собі не змінюється, але використовується для доступу до змінного балансу. Подивіться на різницю між означувачем і значущою ознакою для отримання більш детальної інформації або введення в монади Лейбніца про те, як незмінна річ може представляти незмінність.
Піт Кіркхем

7

Якщо ви google це, ви можете виявити, що в деяких випадках реєстратори не визначаються як статичний остаточний. Додайте до цього кілька швидких копій-n-вставок, і це може пояснити це.

Ми використовуємо LOGGER у всьому своєму коді, і це відповідає нашій умові іменування (і наша CheckStyle задоволена цим).


Ми навіть йдемо далі, користуючись суворою конвенцією про іменування в Eclipse. Ми створюємо новий клас з кодовим шаблоном:

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

Реєстратор коментується, оскільки спочатку він нам не потрібен. Але якщо нам це буде потрібно пізніше, ми просто його відмежуємо.

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

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

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

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


5
Ловля метальних матеріалів - це погана практика, якщо ви не реєструєтесь та не повторно скидаєте її. Пам’ятайте про помилки: 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 пропустить рядок зі своїх чеків, це дозволить вам вибрати будь-який стиль, який ви хочете.


6
Або не використовуйте PMD, вони завжди помиляються, і ваш код ідеальний
IAdapter

1
Якщо вам потрібно щоразу виключати чек, то це не має сенсу.
keiki

Не можу погодитися більше - однак ... корисно знати коментар про виключення
Fortyrunner

3

Зазвичай константи знаходяться в великих літерах.

Однак реєстратори не повинні бути статичними, а шукати кожен "новий" клас, що містить, якщо використовується фасад slf4j. Це дозволяє уникнути деяких неприємних проблем із завантажувачем класів у особливо веб-контейнерах, а також дозволяє рамці реєстратора робити спеціальні речі залежно від контексту виклику.


2

Я віддаю перевагу "реєстратору", тобто нижньому регістру. Причина не в тому, що це постійна чи не константа (змінна чи незмінна). Якщо ми будемо використовувати це міркування, нам доведеться перейменувати змінну, якщо ми змінимо каркас ведення журналу (або якщо фреймворк змінить можливість зміни змінних журналів).

Для мене важливіші інші причини.

  1. Реєстратор - це тіньовий об’єкт у класі і не повинен бути дуже помітним, оскільки він не реалізує основної логіки. Якщо ми використовуємо "LOGGER", це привернення уваги коду, що привертає занадто багато уваги.

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


1

Якщо ваші стандарти кодування - якщо у вас є такі - скажіть, що це повинно бути великими літерами, то так.

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

BTW: Я віддаю перевагу "LOGGER" ;-)

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