Руководство Google по форматированию кода на Java

1. Введение

В данном документе описаны стандарты написания кода на языке программирования Java, принятые в корпорации Google. Исходный файл Java считается соответствующим этим стандартам тогда и только тогда, когда он удовлетворяет всем изложенным здесь правилам.
Затронутые в руководстве темы касаются не только эстетической стороны форматирования, но и других типов соглашений или стандартов написания кода. Тем не менее, данный документ концентрируется в первую очередь на определении строгих правил, которым мы повсеместно следуем, и избегает рекомендаций, соблюдение которых нельзя формально проверить (ни человеком, ни машинными инструментами).

1.1 Терминология

В рамках этого руководства определены следующие термины:
1. Термин класс используется для обозначения обычного класса, класса-записи (record), перечисления (enum), интерфейса или типа аннотации (@interface)
2. Термин член класса используется для обозначения вложенного класса, поля, метода или конструктора, то есть для всех элементов класса верхнего уровня, кроме блоков инициализации
3. Термин комментарий всегда относится к комментариям реализации. Мы не используем словосочетание «комментарии к документации», предпочитая общепринятый термин «Javadoc»
Остальная терминология будет даваться по мере необходимости в разных местах данного руководства.

1.2 Примечание к руководству

Примеры кода в данном документе хоть и соответствуют стилю Google, могут демонстрировать не единственно верный подход к его форматированию. Дополнительные варианты форматирования, использованные в примерах, не должны навязываться как правила.

2. Исходный файл. Основы

2.1 Имя файла

Имя исходного файла состоит из имени класса верхнего уровня, находящегося в нем. Имя является регистрозависимым и заканчивается расширением .java

2.2 Кодировка файла: UTF-8

Исходные файлы имеют кодировку UTF-8.

2.3 Специальные символы

2.3.1 Символы пробела
Помимо последовательности символов конца строки, ASCII-символ горизонтального пробела (0×20) является единственным пробельным символом, встречающимся в исходном файле. Это означает, что:
  1. Все прочие пробельные символы в символьных и строковых литералах, а также в текстовых блоках — экранируются
  2. Символы табуляции не используются для отступов
2.3.2 Специальные экранирующие последовательности
Для символа, у которого имеется специальная escape-последовательность (\b, \t, \n, \f, \r, \s, \", \' и \\), используется именно она, а не соответствующая ей восьмеричная (например, \012) или Unicode (например, \u000a) последовательности.
2.3.3 Символы не из таблицы ASCII
Для символов не из таблицы ASCII используется символ Unicode (например, ∞) или эквивалентная Unicode escape-последовательность (например, \u221e). Предпочтение следует отдавать в пользу тех символов, которые делают код более понятным и читаемым. При этом учитывайте, что использование Unicode escape-последовательностей за пределами строковых литералов и комментариев крайне не рекомендуется.
Совет: при использовании Unicode escape-последовательности и, если это оправдано, при применении непосредственно символов Unicode, рекомендуется такой код сопровождать поясняющими комментариями
Совет: никогда не делайте свой код менее читаемым только из опасения, что некоторые программы не смогут правильно обработать символы не из таблицы ASCII. Если это все же случится, то такие программы следует исправить, поскольку они работают неверно

3. Структура исходного файла

Исходный файл состоит из следующих разделов в указанном порядке:
  1. Информация о лицензии или авторских правах, если имеется
  2. Объявление пакета
  3. Объявление импортов
  4. Объявление одного класса верхнего уровня
Используйте только одну пустую строку в коде для отделения перечисленных элементов друг от друга.
Файл package-info.java имеет такую же структуру, но без объявления класса.
Файл module-info.java не содержит объявления пакета и заменяет объявление класса на объявление модуля, но в остальном следует той же структуре.

3.1 Информация о лицензии или авторских правах, если имеется

Информация о лицензии или авторских правах должна быть размещена в том файле, к которому она относится.

3.2 Объявление пакета

Пакет объявляется без переноса строки. Ограничение на длину строки (Раздел 4.4) на объявление пакета не распространяется.

3.3 Объявления импортов

3.3.1 Символ подстановки при объявлении импортов
Символ подстановки ( * ) при объявлении импортов, статических или обычных, не используется.
3.3.2 Перенос строки
Импорты объявляются без переноса строки. Ограничение на длину строки на них не распространяется (Раздел 4.4).
3.3.3 Упорядочивание и интервал
Импорты упорядочиваются следующим образом:
  1. Все статические импорты размещаются в одном месте, рядом друг с другом
  2. Все не статические импорты также размещаются одной группой
Если объявляются как статические, так и не статические импорты, то эти блоки следует разделить одной пустой строкой. Других пустых строк между импортами быть не должно.
Внутри каждой группы импортируемые классы следуют в порядке сортировки ASCII-символов.
Примечание: это не обычная лексикографическая сортировка строк, так как точка ( . ) стоит в ASCII-таблице раньше точки с запятой ( ; )
3.3.4 Статический импорт вложенных классов
Статический импорт не используется для статических вложенных классов. Такие классы импортируются с объявлением обычного импорта.

3.4 Объявление класса

3.4.1 Объявляется ровно один класс верхнего уровня
Каждый класс верхнего уровня находится в отдельном исходном файле.
3.4.2 Порядок членов класса
Порядок, выбираемый при расположении членов класса и блоков инициализации, может существенно влиять на понимание кода. Однако не существует единственно правильного подхода к этому: разные классы могут упорядочивать свое содержимое по-разному.
Важно, чтобы у каждого класса был такой логический порядок расположения содержимого, который позволил бы программисту, сопровождающему этот код, объяснить его.
Например, новые методы не должны просто механически добавляться в конец класса, так как это приведёт к порядку «по дате добавления», который не является логическим.
3.4.2.1 Перегруженный код не должен быть разделен
Когда у класса есть несколько конструкторов или методов с одинаковым именем, они должны располагаться в одной непрерывной группе без вставок другого кода между ними. Это правило применяется даже если модификаторы, такие как static или private, различаются между методами или конструкторами.

3.5 Объявление модуля

3.5.1 Порядок и разделение директив модуля
Директивы модуля упорядочиваются следующим образом:
  1. Все директивы requires одной группой
  2. Все директивы exports одной группой
  3. Все директивы opens одной группой
  4. Все директивы uses одной группой
  5. Все директивы provides одной группой
Каждая группа отделяется пустой строкой.

4. Форматирование

Терминология
Тело класса, метода, конструктора или оператора switch относится к блочной конструкции.
Обратите внимание, что согласно Разделу 4.8.3.1, любой инициализатор массива также может рассматриваться как блочная конструкция.

4.1 Фигурные скобки

4.1.1 Фигурные скобки используются везде
Фигурные скобки используются с операторами if, else, for, while и do-while, даже если их тело пустое или содержит только одну строку кода.
Другие необязательные фигурные скобки, например в лямбда-выражении, остаются необязательными.
4.1.2 Непустые блоки: стиль K & R
Для непустых блоков и блочных конструкций фигурные скобки ставятся в стиле Кернигана и Ритчи (для наглядности мы решили добавить немного кода, демонстрирующего данные правила — примечание переводчика):
  • Перед открывающейся скобкой переход на новую строку не делается (кроме случаев, описанных далее):
// правильно
if (true) {

// неправильно
if (true)
{
  • Переход на новую строку делается после открывающей скобки:
// правильно
while (true) {
    // some code

// неправильно
while (true) { // some code
  • Переход на новую строку делается перед закрывающей скобкой:
// правильно
for (true) {
    // some code
}

// неправильно
while (true) { /* some code */ }

// неправильно
if (true) {
    /* some code */ }
  • Переход на новую строку делается после закрывающей скобки, только если эта скобка завершает оператор или тело метода, конструктора или именованного (обычного) класса. Переход на новую строку не делается после скобки, если за ней следует else, catch или точка с запятой
Примеры правильно примененных правил:
return () -> {
    while (condition()) {
        method();
   }
};

return new MyClass() {
    @Override public void method() {
        if (condition()) {
            try {
                something();
            } catch (ProblemException e) {
                recover();
            }
        } else if (otherCondition()) {
            somethingElse();
        } else {
            lastThing();
        }
        {
            int x = foo();
            frob(x);
        }
    }
};
Некоторые исключения для перечислений приведены в Разделе 4.8.1
4.1.3 Пустые блоки могут быть сжатыми
Пустой блок или пустая блочная конструкция может быть оформлена в стиле K & R (как описано в Разделе 4.1.2). Также возможно, чтобы такой блок был закрыт сразу после открытия, без символов или разрыва строки внутри {}. Это правило не относится к случаю, когда блок является частью многоблочного оператора, который содержит if-else или try-catch-finally.
// Приемлемо
void doNothing() {}

// Также приемлемо
void doNothingElse() {
}

// Неприемлемо: нельзя использовать пустые блоки в многоблочных операторах
try {
    doSomething();
} catch (Exception e) {}

4.2 Два пробела для отступа

Каждый раз, когда открывается новый блок или блочная конструкция, отступ вправо увеличивается на два пробела (лучше на четыре — примечание переводчика). Когда блок заканчивается, начало следующей строки кода смещается на предыдущий уровень смещения. Уровень смещения применяется как к коду, так и к комментариям внутри блока (см. пример в Разделе 4.1.2).

4.3 Один оператор на каждую строку

Каждый оператор завершается переходом на новую строку.

4.4 Ограничение длины строки в 100 символов

Код на Java имеет ограничение длины строки в 100 символов (из-за распространения широкоформатных мониторов, допустимой шириной является использование до 120 символов — примечание переводчика). Под «символом» понимается любой из элементов Unicode. За исключением случаев, описанных ниже, каждая строка, превышающая это ограничение, должна быть перенесена, как описано в Разделе 4.5.
Исключения:
  1. Строки, в которых соблюдение ограничения невозможно (например, длинный URL в Javadoc или длинная ссылка на метод JSNI)
  2. Объявления package и import (см. Разделы 3.2 и 3.3)
  3. Содержимое текстовых блоков
  4. Строки с командами в комментариях, которые могут быть скопированы и вставлены для выполнения в терминале
  5. Очень длинные идентификаторы, в редких случаях, когда они необходимы, могут превышать ограничение на длину строки. В таком случае допустимый перенос для окружающего кода должен соответствовать результату работы google-java-format

4.5 Перенос строк

Терминология
Действие, когда код мог бы быть размещен на одной строке, но разделяется на несколько строк, называется переносом строк.
Не существует общепринятого правила, определяющего, как именно необходимо выполнять перенос строки в каждой ситуации. Зачастую один и тот же фрагмент кода можно перенести несколькими допустимыми способами.
Примечание: обычно перенос делается с целью избежания превышения допустимой длины строки. Но даже код, умещающийся в это ограничение, по решению автора, может быть перенесен на новую строку.
Совет: выделение вспомогательного метода или локальной переменной может решить проблему без переноса строк кода
4.5.1 Где выполнять перенос
Главное правило переноса строк: предпочитайте разрыв на более высоком синтаксическом уровне. Также:
1. Если строка разрывается не на операторе присваивания, то разрыв следует выполнить перед символом оператора.
Это правило также применимо к следующим «оператороподобным» символам:
  • точка-разделитель ( . )
  • два двоеточия в ссылке на метод ( :: )
  • амперсанд в скобках дженерика <T extends Foo & Bar>
  • вертикальная черта в блоке catch
catch (FooException | BarException e)
2. При разрыве строки на операторе присваивания разрыв обычно ставится после символа, но допустим и разрыв до него. Это также относится к двоеточию в цикле for-each.
3. Имя метода, конструктора или класса-записи при переносе строки остается присоединенным к открывающей скобке «(»
4. Запятая ( , ) при переносе строки остается с предшествующим ей элементом
5. Строка никогда не разрывается рядом со стрелкой в лямбда-выражении или правиле switch, за исключением того, что разрыв может следовать сразу за стрелкой, если текст, следующий за ней, состоит из одного не заключенного в скобки выражения:
MyLambda<String, Long, Object> lambda =
        (String label, Long value, Object obj) -> {
            ...
        };

Predicate<String> predicate = str ->
        longExpressionInvolving(str);

switch (x) {
    case ColorPoint(Color color, Point(int x, int y)) ->
            handleColorPoint(color, x, y);
    ...
}
Примечание: основная цель переноса строки — создание понятного кода, а не кода с наименьшим количеством строк
4.5.2 Отступ продолжения строки на 4 и более пробелов
При переносе строки каждая следующая ее строка-продолжение смещается вправо как минимум на 4 пробела относительно исходной.
Когда продолжений строки несколько, отступ может варьироваться сверх 4-х пробелов по желанию автора. По общему правилу, две подстроки могут иметь одинаковый отступ тогда и только тогда, когда они начинаются с синтаксически параллельных элементов.
В Разделе 4.6.3 рассматривается нерекомендуемая практика использования различного количества пробелов для выравнивания элементов кода относительно предыдущих строк.

4.6 Отступы

4.6.1 Пустые строки
Одна пустая строка всегда ставится:

1. Между расположенными друг за другом членами или инициализаторами класса: полями, конструкторами, методами, вложенными классами, статическими и динамическими блоками инициализации

  • исключение: пустая строка между двумя последовательными полями (между которыми нет другого кода) необязательна. При необходимости пустые строки используются для логического группирования полей
  • исключение: пустые строки между константами перечисления (см. Раздел 4.8.1)
2. В соответствии с другими разделами данного документа (например, Раздел 3 и Разделом 3.3)
Пустая строка также может использоваться в любом месте для повышения читаемости кода, например, между операторами для организации кода в логические блоки. Пустая строка перед первым членом класса, или блоком инициализации, или после последнего члена, или блока инициализации класса не приветствуется, но и не запрещается.
Допускаются несколько последовательных пустых строк, но они никогда не требуются (и не поощряются).
4.6.2 Пробелы
Помимо требований самого языка или прочих правил данного документа, а также не считая литералов, комментариев и Javadoc, одиночные пробелы из таблицы ASCII могут ставиться только в следующих местах:
  1. Между любым ключевым словом (например, if, for или catch) и открывающей скобкой «(», которая следует за ним на той же строке
  2. Между любым ключевым словом (например, else или catch) и закрывающей фигурной скобкой «}», которая предшествует ему на той же строке
  3. Перед любой открывающей фигурной скобкой «{», за исключением:
  • @SomeAnnotation({a, b})
  • String[][] x = {{"foo"}}; - пробел между {{ не требуется согласно п. 9 ниже
4. С обеих сторон любого бинарного или тернарного оператора. Это также относится к следующим «оператороподобным» символам:
  • амперсанд внутри угловых скобок: <T extends Foo & Bar>
  • вертикальная черта в блоке catch, разделяющая несколько исключений: catch (FooException | BarException e)
  • двоеточие ( : ) в for-each
  • стрелка в лямбда-выражении: (String str) -> str.length() или стрелка в switch: case "FOO" -> bar();"
Но это правило не применимо к операторам:
  • два двоеточия ( :: ) в ссылке на метод, которые пишутся как Object::toString
  • точка-разделитель ( . ), которая пишется как object.toString()
5. После ( , : ; ) или закрывающей круглой скобки «)» при приведении типа

6. Между любым содержимым и двойным слэшем ( // ), начинающим комментарий. Допускается несколько пробелов

7. Между двойным слэшем ( // ), начинающим комментарий, и текстом комментария. Допускается несколько пробелов

8. Между типом и идентификатором в объявлении: List<String> list

9. Опционально внутри скобок инициализатора массива. Оба варианта допустимы: new int[] {5, 6} и new int[] { 5, 6 }

10. Между аннотацией типа и [] или ...
Это правило никогда не следует трактовать как требование или запрет на дополнительные пробелы в начале или конце строки; оно относится лишь к внутренним пробелам.
4.6.3 Горизонтальное выравнивание никогда не требуется
Терминология
Горизонтальное выравнивание — это практика добавления различного числа дополнительных пробелов в вашем коде с целью размещения определенных элементов под другими элементами с предыдущей строки.
Эта практика разрешена, но ее использование не требуется данным руководством. Также нет необходимости поддерживать соблюдение выравнивания в тех участках кода, где оно уже было применено.

Пример без выравнивания и с ним:
private int x;       // хорошо
private Color color; // и это тоже

private int   x;      // разрешено, но при редактировании в будущем
private Color color;  // можно оставить без выравнивания
Совет: выравнивание повышает читабельность, но создает проблемы с поддержкой такого кода в будущем. Допустим, требуется изменить только одну строку. Это изменение может исказить форматирование ранее написанного кода, что допускается. Но скорее всего, программист начнет корректировку пробелов, что может запустить каскад из бессмысленных исправлений. Или, в лучшем случае, приведет к искажению информации в истории версий, замедлит ревьюеров и усугубит конфликты слияния. Эти практические соображения имеют приоритет над выравниванием.

4.7 Группирующие скобки рекомендованы

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

4.8 Конкретные конструкции

4.8.1 Перечисления
После каждой запятой, следующей за константой перечисления, перенос строки необязателен. Дополнительные пустые строки (обычно одна) также допускаются. Вот один из возможных вариантов:
private enum Answer {
    YES {
        @Override public String toString() {
            return "yes";
        }
    },

    NO,
    MAYBE
}
Код перечисления без методов и документации, описывающих его константы, может быть отформатирован, как инициализатор массива (см. Раздел 4.8.3.1):
private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
Так как перечисления — это классы, для них следует применять все прочие правила форматирования классов.
4.8.2 Объявления переменных
4.8.2.1 Одна переменная — одно объявление
Каждая переменная (поле или локальная) объявляется только по одной за раз: объявления вида int a, b; не используются.
Исключение: множественные объявления переменных допускаются в заголовке цикла for.
4.8.2.2 Объявляйте переменные в месте их использования
Локальные переменные не принято объявлять в начале содержащего их блока или блочной конструкции. Наоборот, локальные переменные необходимо объявлять максимально близко к месту их первого использования (в разумных пределах), чтобы минимизировать их область видимости. Обычно локальные переменные инициализируются в момент объявления, или же сразу после него.
4.8.3 Массивы
4.8.3.1 Инициализаторы массивов могут быть блочными
Инициализатор массива может быть отформатирован как блочная конструкция. Например, все следующие варианты допустимы (список примеров не полный):
new int[] {           
    0, 1, 2, 3            
}                       
                        
new int[] {             
    0, 1,               
    2, 3
}               

new int[]
    {0, 1, 2, 3}     

new int[] {
    0,
    1,
    2,
    3
}
4.8.3.2 Не объявляйте массивы в стиле языка С
Квадратные скобки ставятся после типа, а не после переменной: String[] args, а не String args[].
4.8.4 Операторы и выражения switch
По историческим причинам в языке Java существует два различных синтаксиса для switch, которые мы можем называть старым и новым стилем. Новый стиль использует стрелку ( -> ) после меток switch, а старый стиль использует двоеточие ( : ).
Терминология
Внутри фигурных скобок блока switch находятся одно либо несколько правил (новый стиль); либо одна или несколько групп операторов (старый стиль). Правило switch состоит из метки switch (case ... или default), за которой следует -> и выражение, блок или оператор throw. Группа операторов состоит из одной или нескольких меток switch, каждая из которых следует за двоеточием, затем одного или нескольких операторов или, для последней группы операторов, нуля или более операторов. (Эти определения соответствуют спецификации языка Java, §14.11.)
4.8.4.1 Отступ
Как и в случае с любым другим блоком, содержимое блока switch смещается на два пробела (здесь и далее лучше на четыре — примечание переводчика). Каждая метка switch начинается с этого отступа.
В новом стиле switch правило может быть записано в одной строке, если оно в остальном соответствует стилю Google (оно не должно превышать ограничение на длину строки, и если оно содержит непустой блок, то после «{» должен быть перенос строки). Применяются правила переноса строк из раздела 4.5, включая отступ +4 пробела для строк-продолжений. Для правила switch с непустым блоком после стрелки применяются те же правила, что и для блоков в других местах: строки между «{» и «}» имеют дополнительный отступ +2 пробела относительно строки с меткой switch.
switch (number) {
    case 0, 1 -> handleZeroOrOne();
    case 2 ->
        handleTwoWithAnExtremelyLongMethodCallThatWouldNotFitOnTheSameLine();
    default -> {
        logger.atInfo().log("Surprising number %s", number);
        handleSurprisingNumber(number);
    }
}
В старом стиле switch двоеточие каждой метки следует за переносом строки. Операторы внутри группы операторов имеют дополнительный отступ +2 пробела.
4.8.4.2 Сквозное выполнение комментируется
В старом стиле switch каждая группа операторов либо завершается явно (с помощью break, continue, return или выбрасывания исключения), либо помечается комментарием, указывающим, что выполнение будет или может продолжиться в следующей группе операторов. Достаточно любого комментария, передающего идею сквозного выполнения (обычно // fall through). Этот специальный комментарий не требуется в последней группе операторов блока switch. Пример:
switch (input) {
    case 1:
    case 2:
        prepareOneOrTwo();
        // fall through
    case 3:
        handleOneTwoOrThree();
        break;
    default:
        handleLargeNumber(input);
}
Обратите внимание, что комментарий ставится не после case 1, а лишь в конце группы операторов.
В новом стиле switch сквозного выполнения нет.
4.8.4.3 Полнота и наличие метки default
Язык Java требует, чтобы выражения switch и многие виды операторов switch
были полными. Это означает, что каждое возможное значение,
по которому может осуществляться переключение, будет соответствовать одной из меток switch. Switch является полным, если в нём есть метка default,
но также, например, если переключаемое значение является перечислением
и каждое значение перечисления соответствует метке switch.
Стиль Google требует, чтобы каждый switch был полным, даже те, где сам
язык этого не требует. Это может потребовать добавления метки default,
даже если она не содержит кода.
4.8.4.4 Выражения switch
Выражения switch должны использовать новый стиль:
return switch (list.size()) {
    case 0 -> "";
    case 1 -> list.getFirst();
    default -> String.join(", ", list);
};
4.8.5 Аннотации
4.8.5.1 Аннотации использования типа
Аннотации использования типа указываются непосредственно перед аннотируемым типом. Аннотация считается аннотацией использования типа, если она помечена метааннотацией @Target(ElementType.TYPE_USE). Пример:
final @Nullable String name;

public @Nullable Person getPersonByName(String name);
4.8.5.2 Аннотации классов, пакетов и модулей
Аннотации, применяемые к объявлению класса, пакета или модуля, указываются сразу после блока документации. Каждая аннотация размещается на отдельной строке (по одной аннотации на строку). Эти переносы строк не считаются переносом строки (см. Раздел 4.5), поэтому уровень отступа не увеличивается. Пример:
/** Класс. */
@Deprecated
@CheckReturnValue
public final class Frozzler { ... }

/** Пакет. */
@Deprecated
@CheckReturnValue
package com.example.frozzler;

/** Модуль. */
@Deprecated
@SuppressWarnings("CheckReturnValue")
module com.example.frozzler { ... }
4.8.5.3 Аннотации методов и конструкторов
Правила для аннотаций в объявлениях методов и конструкторов такие же, как в предыдущем разделе. Пример:
Правила для аннотаций в объявлениях методов и конструкторов такие же, как в предыдущем разделе. Пример:
@Deprecated
@Override
public String getNameIfPresent() { ... }
Исключение: одиночная аннотация без параметров может указываться вместе с первой строкой сигнатуры.
Например:
@Override public int hashCode() { ... }
4.8.5.4 Аннотации полей
Аннотации, применяемые к полю, также указываются сразу после блока документации, но в этом случае несколько аннотаций (возможно, параметризованных) могут быть перечислены в одной строке.
@Partial @Mock DataLoader loader;
4.8.5.5 Аннотации параметров и локальных переменных
Нет конкретных правил для форматирования аннотаций параметров или локальных переменных (за исключением случаев, когда аннотация является аннотацией использования типа).
4.8.6 Комментарии
Этот раздел посвящен комментариям реализации. Javadoc рассматривается отдельно в Разделе 7.
Любому переносу строки может предшествовать произвольное количество пробелов, за которым следует комментарий реализации. Такой комментарий делает строку непустой.
4.8.6.1 Стиль блочных комментариев
Блочные комментарии имеют тот же отступ, что и окружающий код. Они могут быть в стиле /* ... */ или // ... . Для многострочных комментариев вида /* … */ последующие строки должны начинаться с символа *, выравненного по * в предыдущей строке.
/*
 * This is          // And so           /* Or you can
 * okay.            // is this.          * even do this. */
 */
Комментарии не заключаются в рамки, нарисованные звездочками или другими символами.
Совет: при написании многострочных комментариев используйте стиль /* … */, если хотите, чтобы средства автоматического форматирования кода делали перенос строки при необходимости (в стиле параграфов). Большинство средств форматирования не могут делать этого с блоками однострочных комментариев // …
4.8.6.2 Комментарии TODO
Используйте комментарии TODO для кода, который является временным, краткосрочным решением или достаточно хорошим, но не идеальным.
Комментарий TODO начинается со слова TODO заглавными буквами, затем двоеточие и ссылка на ресурс, содержащий контекст, в идеале ссылка на баг. Ссылка на баг предпочтительнее, потому что баги отслеживаются и имеют последующие комментарии. После этого контекста идет дефис, а затем пояснительная строка.
Цель — иметь единый формат TODO, который можно искать для получения подробностей.
// TODO: crbug.com/12345678 - Удалите после окончания срока действия совместимости с версией 2047q4.
Избегайте добавления TODO, которые ссылаются на человека или команду как на контекст:
// TODO: @ваше_имя_пользователя - Создайте заявку и используйте '*' для повтора.
Если ваш TODO имеет форму «Сделать что-то в будущем», убедитесь, что вы указываете либо очень конкретную дату («Исправить к ноябрю 2005 года»), либо очень конкретное событие («Удалить этот код, когда все клиенты смогут обрабатывать XML-ответы»).
4.8.7 Модификаторы
Модификаторы классов и полей, если они присутствуют, отображаются в порядке, рекомендованном спецификацией языка Java:
public protected private abstract default static final sealed
non-sealed transient volatile synchronized native strictfp
Модификаторы директив requires для модулей, если они присутствуют, располагаются в следующем порядке:
transitive static
4.8.8 Числовые литералы
Целочисленные литералы типа long используют суффикс L в верхнем регистре, никогда в нижнем (чтобы избежать путаницы с цифрой 1). Например, 3000000000L, а не 3000000000l.
4.8.9 Текстовые блоки
Открывающие """ текстового блока всегда находятся на новой строке. Эта строка может либо следовать тем же правилам отступа, что и другие конструкции, либо вообще не иметь отступа (начинаться с левого поля). Закрывающие """ находятся на новой строке с тем же отступом, что и открывающие """, и могут следовать в той же строке за дополнительным кодом. Каждая строка текста в текстовом блоке имеет отступ не менее, чем открывающие и закрывающие """ (если строка имеет больший отступ, то строковый литерал, определяемый текстовым блоком, будет содержать пробелы в начале этой строки).

Содержимое текстового блока может превышать ограничение на длину строки.

5. Именование

5.1 Общие правила для всех идентификаторов

Идентификаторы используют только буквы и цифры ASCII и, в некоторых отмеченных ниже случаях, символы подчеркивания.
Таким образом, каждое допустимое имя идентификатора соответствует регулярному выражению \w+. (буквенно-цифровой символ, встречающийся один или более раз — примечание переводчика ).
Стилю данного руководства не соответствуют имена, использующие специальные суффиксы или префиксы, например: name_, mName, s_name или kName.

5.2 Правила для разных типов идентификаторов

5.2.1 Имена пакетов и модулей
Имена пакетов и модулей используют только строчные буквы и цифры (без подчёркиваний). Последовательные слова просто объединяются.
Правильно: com.example.deepspace
Неправильно: com.example.deepSpace или com.example.deep_space
5.2.2 Имена классов
Имена классов именуются в стиле UpperCamelCase (с заглавной первой буквой).
Имена классов обычно являются существительными или словосочетаниями с существительными. Например, Character или ImmutableList.
Имена интерфейсов также могут быть существительными или словосочетаниями с существительными (например, List), но иногда могут быть прилагательными или сочетаниями с прилагательными (например, Readable).
Не существует конкретных правил или устоявшихся соглашений для именования типов аннотаций.
Имя тестового класса должно заканчиваться словом Test, например HashIntegrationTest. Если он тестирует один класс, его имя состоит из имени этого класса плюс Test, например, HashImplTest.
5.2.3 Имена методов
Имена методов записываются в стиле lowerCamelCase (с маленькой первой буквой).
Имена методов обычно являются глаголами или словосочетаниями с глаголами. Например, sendMessage или stop.
В именах методов тестов JUnit могут использоваться подчёркивания для разделения логических компонентов имени, причём каждый компонент записывается в стиле lowerCamelCase, например, transferMoney_deductsFromSource. Не существует единственно правильного способа именования тестовых методов.
5.2.4 Имена констант
Имена констант используют стиль UPPER_SNAKE_CASE: все буквы заглавные, каждое слово отделено от следующего одним символом подчеркивания. Но что именно считается константой?
Константами являются static final поля, содержимое которых является глубоко неизменяемым, а методы не имеют обнаруживаемых побочных эффектов. Такими константами являются примитивы, переменные типа String, неизменяемые классы и всё, что установлено в null. Если какое-либо наблюдаемое состояние объекта может измениться, он не является константой. Простого намерения никогда не изменять объект недостаточно.
Примеры:
// Константы
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
static final Map<String, Integer> AGES = ImmutableMap.of("Ed", 35, "Ann", 32);
static final Joiner COMMA_JOINER = Joiner.on(','); // поскольку Joiner неизменяем
static final SomeMutableType[] EMPTY_ARRAY = {};

// Не константы
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 ImmutableMap<String, SomeMutableType> mutableValues =
    ImmutableMap.of("Ed", mutableInstance, "Ann", mutableInstance2);
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};
Имена констант обычно являются существительными или словосочетаниями с существительными.
5.2.5 Имена не константных полей
Имена не константных полей (статических или нет) записываются в стиле lowerCamelCase.
Имена таких полей обычно являются существительными или словосочетаниями с существительными. Например, computedValues или index.
5.2.6 Имена параметров
Имена параметров записываются в стиле lowerCamelCase.
В публичных методах следует избегать имен параметров, состоящих из одного символа.
5.2.7 Имена локальных переменных
Имена локальных переменных записываются в стиле lowerCamelCase.
Даже будучи финальными и неизменяемыми, локальные переменные не считаются константами и не должны оформляться в их стиле.
5.2.8 Имена переменных типа
Каждая переменная типа именуется одним из двух стилей:
  • Одна заглавная буква, опционально с последующей одной цифрой (например, E, T, X, T2)
  • Имя в форме, используемой для классов (см. Раздел 5.2.2), с добавлением заглавной буквы T (например, RequestT, FooBarT).

5.3 «Верблюжий» стиль (camelCase)

Иногда существует более одного способа преобразовать фразу на английском языке в «верблюжий» стиль, как например в случае с аббревиатурами или нестандартными выражениями вроде «IPv6» или «iOS».
Для повышения предсказуемости, данное руководство задает следующую (примерную) схему.
Начинаем с исходной формы имени:
1. Преобразуйте фразу в обычный ASCII и удалите все апострофы. Например, «Müller's algorithm» можно преобразовать в «Muellers algorithm»
2. Разделите полученный результат на слова, отбрасывая пробелы и оставшиеся знаки препинания (обычно дефисы):
  • рекомендация: если какое-либо слово уже имеет общепринятую форму в «верблюжьем» стиле, разделите его на составные части (например, «AdWords» преобразуется в «ad words»). Обратите внимание, что слово «iOS» записывается не совсем в «верблюжьем» стиле; оно не соответствует каким-либо соглашениям, поэтому данная рекомендация не применяется.
3. Теперь преобразуйте все в нижний регистр (включая аббревиатуры), затем измените в верхний регистр первый символ:
  • … в каждом слове, чтобы получить UpperCamelCase, или
  • … в каждом слове, кроме первого, чтобы получить lowerCamelCase
4. Наконец, объедините все слова в один идентификатор. Обратите внимание, что регистр исходных слов почти полностью игнорируется.
В очень редких случаях (например, многокомпонентные номера версий) может потребоваться использовать подчёркивания для разделения соседних чисел, поскольку числа не имеют вариантов верхнего и нижнего регистра.
Примеры:
*Допустимо, но не рекомендуется.
Примечание: некоторые слова в английском языке могут писаться через дефис по-разному: например, «nonempty» и «non-empty» оба правильны, поэтому имена методов checkNonempty и checkNonEmpty также оба правильны.

6. Практика программирования

6.1 Всегда используйте @Override

Аннотацию @Override следует указывать для метода, когда:
  • Метод класса переопределяет метод суперкласса
  • Метод класса реализует метод интерфейса
  • Метод интерфейса переопределяет метод суперинтерфейса
  • Метод-аксессор объявляется явно для компонента записи (record)
Исключение: аннотация может быть опущена, когда родительский метод помечен как @Deprecated

6.2 Не игнорируйте пойманные исключения

Очень редко возникают ситуации, когда не нужно предпринимать никаких действий в ответ на пойманное исключение (типичным решением является занесение его в лог или, если исключение считается «невозможным», повторно выбросить его как AssertionError).
Ниже приведен пример с поясняющим комментарием, когда действительно уместно не предпринимать никаких действий в блоке catch:
try {
    int i = Integer.parseInt(response);
    return handleNumericResponse(i);
} catch (NumberFormatException ok) {
    // Это не число; это нормально, просто продолжаем
}
return handleTextResponse(response);

6.3 Обращение к статическим членам через имя класса

Обращаться к статическому члену класса необходимо через имя класса, а не по ссылке на объект или по выражению, возвращающему этот объект:
Foo aFoo = ...;
Foo.aStaticMethod(); // правильно
aFoo.aStaticMethod(); // неправильно
somethingThatYieldsAFoo().aStaticMethod(); // неправильно

6.4 Не используйте финализаторы

Не переопределяйте Object.finalize. Поддержка финализации запланирована к удалению.

7. Javadoc

7.1 Форматирование

7.1.1 Основная форма
Основной способ форматирования блоков Javadoc показана в следующем примере:
/**
 * Многострочный текст Javadoc пишется здесь,
 * с обычным переносом строк...
 */
public int method(String p1) { ... }
… или в одну строку:
/** Особенно короткий текст Javadoc. */
В большинстве случаев следует использовать основной способ форматирования многострочных комментариев. Однострочная форма может использоваться, когда весь блок Javadoc (включая маркеры комментария) помещается в одну строку. Обратите внимание, что это применимо лишь тогда, когда нет блочных тегов, таких как @param.
7.1.2 Абзацы
Одна пустая строка, т.е. строка, содержащая только выровненную начальную звездочку «*», используется между абзацами и перед группой блочных тегов, если таковые имеются. Каждый абзац, кроме первого, начинается с <p> непосредственно перед первым словом, без пробела после него. HTML-теги других блочных элементов, таких как <ul> или <table>, не предваряются тегом <p>.
7.1.3 Блочные тэги
Все блочные теги следует размещать в таком порядке: @param, @return, @throws, @deprecated. Эти четыре тега никогда не используются с пустым описанием. Если тег блока не помещается в одну строку, продолжение строки имеет отступ +4 (или более) пробела от позиции @.

7.2 Краткое описание метода

Каждый блок Javadoc начинается с краткого описания. Это описание очень важно: оно является единственной частью текста, которая присутствует в определенных контекстах, таких как индексы классов и методов.
Это описание обычно состоит из словосочетания с существительным или глаголом, а не является законченным предложением. Оно не начинается с
A {@code Foo} is a… или This method returns…, а также не образует законченного повелительного предложения, например, Save the record. Однако описание должно начинаться с заглавной буквы и заканчиваться точкой, как если бы это было полноценное предложение.
Совет: Распространенной ошибкой является написание Javadoc в виде
/** @return the customer ID */.
Это неверно и должно быть исправлено на
/** Returns the customer ID. */.
или
/** {@return the customer ID} */

7.3 Где использовать Javadoc

Как минимум, Javadoc следует использовать для каждого видимого класса, члена или компонента записи, за исключением некоторых случаев, описанных ниже.
Класс верхнего уровня является видимым, если он public; член является видимым, если он public или protected и его содержащий класс видим; компонент записи является видимым, если его содержащая запись видима.
Дополнительное содержимое Javadoc также может присутствовать, как объяснено в Разделе 7.3.4.
7.3.1 Исключение: самоочевидные члены
Javadoc опционален для простых и очевидных методов, таких как getFoo, в тех случаях, когда действительно нельзя сказать ничего более, чем «Возвращает foo».
Важно: неуместно ссылаться на это исключение, чтобы оправдать пропуск соответствующей информации, которую может потребоваться обычному читателю
Например, для метода с названием getCanonicalName не игнорируйте написание документации (с тем основанием, что имя метода говорит лишь
/** Возвращает каноническое имя. */), поскольку обычный человек, читающий код, может не знать, что означает термин «каноническое имя»!
7.3.2 Исключение: переопределение
Javadoc не всегда сопровождает метод, который переопределяет метод из супер-класса (или супер-интерфейса).
7.3.3 Необязательный Javadoc
Прочие классы и члены сопровождаются Javadoc по необходимости или по желанию.
Всякий раз, когда комментарий реализации будет использоваться для определения общей цели или поведения класса, или члена, этот комментарий записывается как Javadoc (с использованием /**).
Необязательный Javadoc не обязательно должен следовать правилам форматирования Разделов 7.1.2, 7.1.3 и 7.2, хотя это, конечно, рекомендуется.
Оригинал статьи «Google Java Style Guide»
Оцените статью, если она вам понравилась!