Соглашение об именах Java для статических конечных переменных

существует правило, которое гласит:

Имена, представляющие константы (конечные переменные), должны быть заглавными использование подчеркивания для разделения слов (взято из http://geosoft.no/development/javastyle.html)

который отлично работает для примитивных типов, таких как int или string:

private static final int MAX_COUNT = 10;

Но как насчет не примитивных типов? В большинстве случаев я видел следующее:

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

или в одиночных точках, где переменная экземпляра не находится в верхнем регистре.

Вопрос в том, что является правильным способом объявить эти типы переменных (например, журнал и экземпляр)?

Ответ 1

Это все еще постоянное. См. JLS для получения дополнительной информации относительно соглашения об именах для констант. Но на самом деле все это зависит от предпочтений.


Имена констант в типах интерфейсов должны быть, а finalпеременные типов классов обычно могут быть, последовательность одного или больше слов, сокращений или аббревиатур, все прописные буквы, с компонентами разделенных символами подчеркивания "_". Константные имена должны быть описательный и не излишне сокращенный. Обычно они могут быть любой подходящей частью речи. Примеры имен констант включают MIN_VALUE, MAX_VALUE, MIN_RADIX и MAX_RADIXclass Character.

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

interface ProcessStates {
  int PS_RUNNING = 0;
  int PS_SUSPENDED = 1;
}

Обнуление включений постоянных имен редко:

  • У константных имен обычно нет строчных букв, поэтому они обычно не будут скрывать имена пакетов или типов, и обычно они не будут теневыми полями, имена которых обычно содержат по крайней мере одну строчную букву.
  • Константные имена не могут скрывать имена методов, потому что они отличаются синтаксически.

Ответ 2

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

Аннотация и интерфейс

При именовании интерфейсов и абстрактных классов принятое соглашение превратилось в не префикс или суффикс вашей abstract class или interface с любой идентифицирующей информацией, которая указывала бы, что это что-то иное, чем класс.

public interface Reader {}
public abstract class FileReader implements Reader {}
public class XmlFileReader extends FileReader {}

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

Статический финал

Мои личные предпочтения и убеждения заключаются в том, что мы должны следовать аналогичной логике, ссылаясь на переменные static final. Вместо этого мы оцениваем его использование при определении того, как его назвать. Кажется, что все аргументы в верхнем регистре - это то, что было несколько слепо принято на языках C и С++. По моему мнению, это не оправдание продолжения традиции на Java.

Вопрос о намерении

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

public class ChatMessage {
    //Used like a private variable
    private static final Logger logger = LoggerFactory.getLogger(XmlFileReader.class);

    //Used like an Enum
    public class Error {
        public static final int Success = 0;
        public static final int TooLong = 1;
        public static final int IllegalCharacters = 2;
    }

    //Used to define some static, constant, publicly visible property
    public static final int MAX_SIZE = Integer.MAX_VALUE;
}

Не могли бы вы использовать все прописные буквы во всех трех сценариях? Абсолютно, но я думаю, можно утверждать, что это умаляет цель каждого. Итак, рассмотрим каждый случай индивидуально.


Назначение: Частная переменная

В случае вышеприведенного примера Logger регистратор объявляется как закрытый и будет использоваться только внутри класса или, возможно, для внутреннего класса. Даже если он был объявлен в protected или package видимости, его использование одно и то же:

public void send(final String message) {
    logger.info("Sending the following message: '" + message + "'.");
    //Send the message
}

Здесь нам все равно, что Logger является переменной-членом static final. Это может быть просто переменная экземпляра final. Мы не знаем. Нам не нужно знать. Все, что нам нужно знать, это то, что мы регистрируем сообщение для регистратора, предоставленного экземпляром класса.

public class ChatMessage {
    private final Logger logger = LoggerFactory.getLogger(getClass());
}

Вы не назовете его Logger в этом сценарии, так почему вы должны называть его прописным, если он был static final? Его контекст или намерение одинаковы в обоих обстоятельствах.

Примечание. Я изменил свою позицию на видимость package, потому что она больше похожа на форму доступа public, ограниченную уровнем package.


Назначение: Enum

Теперь вы можете сказать, почему вы используете static final целые числа как enum? Это дискуссия которая все еще развивается, и я бы даже сказал, что это противоречиво, поэтому я постараюсь не допустить этого обсуждения надолго, зайдя в него. Однако было бы предложено реализовать следующий принятый шаблон перечисления:

public enum Error {
    Success(0),
    TooLong(1),
    IllegalCharacters(2);

    private final int value;

    private Error(final int value) {
        this.value = value;
    }

    public int value() {
        return value;
    }

    public static Error fromValue(final int value) {
        switch (value) {
        case 0:
            return Error.Success;
        case 1:
            return Error.TooLong;
        case 2:
            return Error.IllegalCharacters;
        default:
            throw new IllegalArgumentException("Unknown Error value.");
        }
    }
}

Существуют вариации выше, которые достигают той же цели, что и явное преобразование enum->int и int->enum. В области потоковой передачи этой информации по сети, встроенная сериализация Java просто слишком многословна. Простые int, short или byte могут сэкономить огромную полосу пропускания. Я мог бы вникать в длительное сравнение и отличие от плюсов и минусов enum vs static final int, связанных с безопасностью, удобочитаемостью, ремонтопригодностью и т.д.; к счастью, это выходит за рамки этого обсуждения.

В нижней строке это, иногда static final int будет использоваться как a enum.

Если вы можете заставить себя согласиться с тем, что приведенное выше утверждение верно, мы можем последовать этому обсуждению стиля. При объявлении enum принятый стиль говорит о том, что мы не делаем следующее:

public enum Error {
    SUCCESS(0),
    TOOLONG(1),
    ILLEGALCHARACTERS(2);
}

Вместо этого мы делаем следующее:

public enum Error {
    SUCCESS(0),
    TOOLONG(1),
    ILLEGALCHARACTERS(2);
}

Если ваш блок целых чисел static final является свободным enum, то почему вы должны использовать для него другое соглашение об именах? Его контекст или намерение одинаковы в обоих обстоятельствах.


Назначение: статическое, постоянное, общедоступное свойство

Этот пример использования, пожалуй, самый пасмурный и спорный из всех. Пример использования статического константного размера - это место, где это чаще всего встречается. Java устраняет необходимость в sizeof(), но есть моменты, когда важно знать, сколько байтов займет структура данных.

Например, считайте, что вы пишете или читаете список структур данных в двоичном файле, а формат этого двоичного файла требует, чтобы общий размер блока данных был вставлен перед фактическими данными. Это распространено, так что читатель знает, когда данные останавливаются в сценарии, что есть больше, не связанных, данных, которые следует. Рассмотрим следующий формат файла:

File Format: MyFormat (MYFM) for example purposes only
[int filetype: MYFM]
[int version: 0] //0 - Version of MyFormat file format
[int dataSize: 325] //The data section occupies the next 325 bytes
[int checksumSize: 400] //The checksum section occupies 400 bytes after the data section (16 bytes each)
[byte[] data]
[byte[] checksum]

Этот файл содержит список объектов MyObject, сериализованных в поток байтов и записанных в этот файл. Этот файл имеет 325 байт объектов MyObject, но без знания размера каждого MyObject у вас нет способа узнать, какие байты принадлежат каждому MyObject. Итак, вы определяете размер MyObject на MyObject:

public class MyObject {
    private final long id; //It has a 64bit identifier (+8 bytes)
    private final int value; //It has a 32bit integer value (+4 bytes)
    private final boolean special; //Is it special? (+1 byte)

    public static final int SIZE = 13; //8 + 4 + 1 = 13 bytes
}

Структура данных MyObject будет занимать 13 байтов при записи в файл, как определено выше. Зная это, читая наш двоичный файл, мы можем динамически определить количество MyObject объектов в файле:

int dataSize = buffer.getInt();
int totalObjects = dataSize / MyObject.SIZE;

Это, по-видимому, типичный случай использования и аргумент для всех заглавных констант static final, и я согласен, что в этом контексте все прописные буквы имеют смысл. Вот почему:

В Java нет класса struct, такого как язык C, но struct - это просто класс со всеми открытыми членами и без конструктора. Это просто данные struct. Итак, вы можете объявить class в struct следующим образом:

public class MyFile {
    public static final int MYFM = 0x4D59464D; //'MYFM' another use of all uppercase!

    //The struct
    public static class MyFileHeader {
        public int fileType = MYFM;
        public int version = 0;
        public int dataSize = 0;
        public int checksumSize = 0;
    }
}

Позвольте мне предисловие к этому примеру, заявив, что лично я не буду разбираться таким образом. Вместо этого я предлагаю неизменяемый класс, который обрабатывает синтаксический анализ внутренне, принимая в качестве аргументов конструктора переменные ByteBuffer или все 4. Тем не менее, доступ (установка в этом случае), этот элемент struct будет выглядеть примерно так:

MyFileHeader header = new MyFileHeader();
header.fileType     = buffer.getInt();
header.version      = buffer.getInt();
header.dataSize     = buffer.getInt();
header.checksumSize = buffer.getInt();

Это не static или final, но они являются публично открытыми участниками, которые могут быть напрямую установлены. По этой причине, я думаю, что когда участник static final публично раскрывается, имеет смысл полностью загладить его. Это тот момент, когда важно отличить его от общедоступных нестатических переменных.

Примечание. Даже в этом случае, если разработчик попытался установить переменную final, они будут встречены либо с ошибкой IDE, либо с компилятором.


Резюме

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

Методология 1: оценка контекста и намерения [highly subjective; logical]

  • Если это переменная private, которая должна быть неотличимой от переменной экземпляра private, тогда назовите их одинаково. все строчные буквы
  • Если это намерение состоит в том, чтобы служить в качестве типа блока стиля enum стиля static, тогда назовите его так же, как и enum. pascal case: начальная шапка каждое слово
  • Если это намерение состоит в том, чтобы определить какое-либо общедоступное, постоянное и статическое свойство, то пусть оно выделяется, делая все заглавные буквы

Методология 2: Частный vs Публичный [objective; logical]

Методология 2 в основном конденсирует свой контекст в видимость и не оставляет места для интерпретации.

  • Если он private или protected, тогда он должен быть строчным.
  • Если он public или package, тогда он должен быть прописным.

Заключение

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

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

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

Ответ 3

Язык не волнует. Важно следить за установленными стилями и условностями проекта, над которым вы работаете, чтобы другие сопровождающие (или вы через пять месяцев) имели наилучшие шансы не путать.

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

Ответ 4

Хорошо, это очень интересный вопрос. Я бы разделил две константы в вашем вопросе в соответствии с их типом. int MAX_COUNT является константой примитивного типа, а Logger log является не-примитивным типом.

Когда мы используем константу примитивных типов, мы изменяем константу только один раз в нашем коде public static final in MAX_COUNT = 10, и мы просто обращаемся к значению константы в другом месте for(int i = 0; i<MAX_COUNT; i++). Именно по этой причине нам удобно использовать это соглашение.

Хотя в случае непримитивных типов, хотя мы инициализируем константу только в одном месте private static final Logger log = Logger.getLogger(MyClass.class);, мы, как ожидается, будем мутировать или вызывать метод по этой константе в другом месте log.debug("Problem"). Мы, ребята, не любим ставить оператор точки после символов столицы. В конце концов, мы должны поместить имя функции после оператора точки, который, несомненно, будет именем верблюда. Вот почему log.debug("Problem") выглядел бы неловко.

То же самое относится к типам String. Обычно мы не мутируем или не вызываем метод в константе String в нашем коде и почему мы используем соглашение об именах капитала для объекта типа String.

Ответ 5

Нет "правильного" способа - существуют только условные обозначения. Вы указали наиболее распространенное соглашение, и тот, который я следую в своем собственном коде: все статические финалы должны быть во всех шапках. Я полагаю, что другие команды следуют другим соглашениям.

Ответ 6

По-моему, переменная, являющаяся "константой", часто является деталью реализации и не обязательно оправдывает различные соглашения об именах. Это может помочь в удобочитаемости, но в некоторых случаях это может повредить.

Ответ 7

Постоянная ссылка на объект не является константой, это просто постоянная ссылка на объект.

private static final не является тем, что определяет что-то постоянным или нет. Это просто способ Java для определения константы, но это не означает, что каждое объявление private static final было помещено там для определения константы.

Когда я пишу private static final Logger, я не пытаюсь определить константу, я просто пытаюсь определить ссылку на объект, который private (что он недоступен из других классов), static (что это переменная уровня класса, не требуется экземпляра) и final (который может быть назначен только один раз). Если это совпадает с тем, как Java ожидает, что вы объявите постоянную, ну, неудачу, но это не делает ее постоянной. Мне все равно, что говорит компилятор, сонар или любой Java-гуру. Постоянное значение, например MILLISECONDS_IN_A_SECOND = 1000, - это одно, а постоянная ссылка на объект - другая.

Золото, как известно, светит, но не все, что сияет, - это золото.

Ответ 8

Эти переменные являются константами, т.е. private static final, указаны ли они во всех кепках или нет. Соглашение all-caps просто делает более очевидным, что эти переменные предназначены для констант, но это не требуется. Я видел

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

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

Ответ 9

Не живите фанатично с соглашениями, которые SUN мешают, делайте то, что вам нравится и ваша команда.

Например, так затмение делает это, нарушая соглашение. Попробуйте добавить implements Serializable, и eclipse попросит вас создать эту строку для вас.

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