Соглашение о кодировании (code convention) – это набор правил и рекомендаций, которые определяют, как нужно писать код на определённом языке программирования (для разных языков – разные соглашения).
Для компьютера стиль кода не имеет значения, однако он играет важную роль при чтении кода человеком. Наше зрение работает таким образом, что вначале мы обращаем внимание на общий образ и структуру, и лишь затем начинаем углубляться в детали. Когда блоки текста в коде выглядят упорядоченно и стандартно, разработчик может легко определить, какая конструкция представлена перед ним, даже не вглядываясь в сам код.
Поэтому были разработаны специальные конвенции. Познакомимся с конвенцией по написанию кода на языке Java.
Содержание:
Файлы и пакеты
Файлы
Файлы с исходным кодом на Java должны называться по названию класса и иметь расширение “.java”.
Неправильно:
1 |
myclass.java |
Правильно:
1 |
MyClass.java |
В каждом файле исходного кода, как правило, размещается только один класс. Когда private-классы и интерфейсы связаны с public-классом, их можно поместить в тот же исходный файл, что и public-класс. Публичный класс (или интерфейс) должен идти первым в файле.
Длина файлов в общей сложности не должна превышать 2000 строк. Первая строка файла, не являющаяся комментарием, должна содержать в себе название пакета:
1 |
package com.example.app; |
Пакеты
Пакеты именуются с маленькой буквы и разделяются точками.
Неправильно:
1 |
Com.Example.MyApp |
Правильно:
1 |
com.example.myapp |
Импорты
Инструкции import должны размещаться в файле через одну пустую строку после названия пакета:
1 2 3 4 |
package com.example.app; import com.example.app.FirstClassName; import com.example.app.SecondClassName; |
Для импортирования класса следует использовать import-инструкцию для отдельного класса, а не сокращённую запись с *. Например, импортирование списка ArrayList.
Неправильно:
1 |
import java.util.*; |
Правильно:
1 |
import java.util.ArrayList; |
Строки
Фигурные скобки
Открывающая фигурная скобка не должна располагаться на отдельной строке. Закрывающая фигурная скобка располагается на отдельной строке.
Неправильно:
1 2 3 4 |
if (condition) { statements; } |
Правильно:
1 2 3 |
if (condition) { statements; } |
Длина строки
“Избегайте строк длиной более 80 символов, так как они плохо обрабатываются многими терминалами и инструментами” – так написано в Java Code Convention 1997-го года. На текущий момент экраны стали удобнее и шире, потому можно поднять этот предел до примерно 120 символов в строке. Но лучше не перебарщивать с длинными строками.
Переносы строк
Если выражение не помещается в одну строку, разбивайте его в соответствии с общими принципами:
- Разрыв после запятой.
- Разрыв перед оператором.
- Предпочитайте разрывы более высокого уровня разрывам более низкого уровня.
- Выравнивайте новую строку по началу выражения того же уровня на предыдущей строке.
- Если вышеуказанные правила приводят к путанице в коде или к тому, что код прижимается к правому краю, просто сделайте отступ слева в 8 пробелов (2 табуляции по 4 пробела).
Неправильно:
1 2 |
longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; |
Правильно:
1 2 |
longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; |
Отступы
В качестве единицы отступа следует использовать четыре пробела. Однако точная конструкция отступа (пробелы и табуляции) не определена.
Отделение операторов друг от друга
Один оператор – одна строка. Одно объявление – одна строка.
Неправильно:
1 |
int x, y, z; variable++; |
Правильно:
1 2 3 4 |
int x; int y; int z; variable++; |
Пустые строки
Пустыми строками следует отделять:
- название пакета вверху файла от перечисления импортов;
- объявление класса от перечисления импортов;
- блок с объявлением полей класса от блока конструкторов;
- конструкторы друг от друга;
- блок конструкторов от блока методов;
- методы друг от друга;
- смысловые единицы в коде.
Пробелы
Нужно обрамлять пробелами все операторы.
Неправильно:
1 |
int result=7+8*12-variable; |
Правильно:
1 |
int result = 7 + 8 * 12 - variable; |
Названия
Классы и интерфейсы
Названия классов и интерфейсов должны начинаться с большой буквы и продолжаться CamelCase-ом.
Неправильно:
1 |
public class myfirstclass |
Неправильно:
1 |
public class myFirstClass |
Неправильно:
1 |
public class MY_FIRST_CLASS |
Правильно:
1 |
public class MyFirstClass |
Методы
Методы должны начинаться с маленькой буквы и продолжаться CamelCase-ом.
Неправильно:
1 |
public int CalculateSum() |
Правильно:
1 |
public int calculateSum() |
Переменные
Все переменные должны начинаться с маленькой буквы и продолжаться CamelCase-ом.
Неправильно:
1 |
String BiGsTrInG = "Small String"; |
Правильно:
1 |
String bigString = "Small String"; |
Константы
Все названия констант должны прописываться SneakCase-ом верхнего регистра.
Неправильно:
1 |
final int bit_count_in_byte = 8; |
Правильно:
1 |
final int BIT_COUNT_IN_BYTE = 8; |
Аббревиатуры и сокращения
Сокращения при именовании классов, интерфейсов, методов, переменных и всего прочего – нежелательны. Они в принципе понижают понятность кода, а выигрыш в краткости записи совсем небольшой.
Неправильно:
1 |
class Btn, int lstId, class CurPage, String fName |
Правильно:
1 |
class Button, int lastId, class CurrentPage, String firstName |
Аббревиатуры следует представлять в виде слов (а не в верхнем регистре). Это более удобочитаемо, особенно, если название состоит из нескольких слов.
Неправильно:
1 |
class HTMLPage, int userID, class HTTPRequest, String URL |
Правильно:
1 |
class HtmlPage, int userId, class HttpRequest, String url |
Транслитерация
В общем-то, просто не используйте транслитерацию.
Неправильно:
1 |
schet, kolichestvo, tovar, fio |
Правильно:
1 |
account, amount, product, fullName |
Операторы
If-then-else
Блоки условий if-then-else должны иметь следующий вид:
1 2 3 |
if (condition) { statements; } |
1 2 3 4 5 |
if (condition) { statements; } else { statements; } |
1 2 3 4 5 6 7 |
if (condition) { statements; } else if (condition) { statements; } else if (condition) { statements; } |
Неправильно:
1 2 |
if (condition) statements; |
For
Цикл for должен иметь следующий вид:
1 2 3 |
for (initialization; condition; update) { statements; } |
Пустой цикл for выглядит так:
1 |
for (initialization; condition; update); |
While
Цикл while должен принимать следующую форму:
1 2 3 |
while (condition) { statements; } |
Пустой цикл while:
1 |
while (condition); |
Do-while
Цикл do-while в коде должен выглядеть так:
1 2 3 |
do { statements; } while (condition); |
Switch-case
Блок switch-case по правилам должен иметь такой вид:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
switch (condition) { case ABC: statements; /* проходит дальше */ case DEF: statements; break; case XYZ: statements; break; default: statements; break; } |
Каждый раз, когда case не завершается (то есть не содержит оператора break), добавляйте комментарий там, где обычно находится оператор break. Это показано в предыдущем примере кода. Каждый оператор switch должен содержать default. Прерывание в случае default является избыточным, но это предотвращает ошибку, если позже будет добавлен другой case.
Try-catch
Выражение try-catch в Java должно принимать следующий вид:
1 2 3 4 5 |
try { statements; } catch (ExceptionClass e) { statements; } |
Return
Оператор return со значением в большинстве случаев не должен использовать скобки. Скобки допустимы, если они делают возвращаемое значение более понятным.
1 2 3 |
return; return myDisk.size(); return (size > defaultSize ? size : defaultSize); |
Местоположение
Фрагменты класса
В классе в самом верху стоят статические поля, затем поля экземпляра. После этого идут конструкторы, затем методы. Причём нет необходимости размещать сначала только публичные методы, а затем приватные – упор следует делать на читаемость кода, для чего лучше группировать методы по функционалу, нежели по уровню доступности или статичности.
Локальные переменные
Объявления должны располагаться в начале блоков (блок – это любой код, ограниченный фигурными скобками { и }). Не тяните с объявлением переменных до их первого использования; это может запутать другого программиста и помешать переносимости кода в пределах области видимости.
1 2 3 4 5 6 7 |
private void MyMethod() { int int1; // начало блока метода if (condition) { int int2; // начало блока if ... } } |
Единственным исключением из правила являются переменные-счётчики циклов for, которые в Java могут быть объявлены в самом операторе for:
1 |
for (int i = 0; i < maxLoops; i++) { ... |
Старайтесь инициализировать локальные переменные там, где они объявлены. Единственная причина не инициализировать переменную там, где она объявлена, – это если её начальное значение зависит от того, какие вычисления сперва произойдут.
Комментарии
Комментарии должны использоваться для обзора кода и предоставления дополнительной информации, которая недоступна в самом коде. Комментарии должны содержать только ту информацию, которая имеет отношение к чтению и пониманию программы. Однако стоит быть осторожными. Как правило, частота комментариев иногда отражает низкое качество кода. Если вы чувствуете, что вынуждены добавить комментарий, подумайте о том, чтобы переписать код, сделав его более понятным, избежав использования комментария.
Обычные комментарии
Программы могут иметь четыре стиля обычных комментариев: блочный, однострочный, трейлерный и end-of-line-комментарий.
Блочные комментарии используются для описания файлов, методов, структур данных и алгоритмов. Блочные комментарии внутри функции или метода должны быть отступом того же уровня, что и описываемый ими код. Перед блочным комментарием должна быть пустая строка, чтобы отделить его от остального кода. Блочные комментарии имеют звездочку “*” в начале каждой строки, кроме первой.
1 2 3 |
/* * Это блочный комментарий */ |
Короткие комментарии могут располагаться в одной строке с отступом до уровня следующего за ними кода.
1 2 3 4 |
if (condition) { /* Обработать условие */ ... } |
Очень короткие комментарии (трейлерные) могут располагаться в той же строке, что и описываемый ими код, но должны быть сдвинуты достаточно далеко, чтобы отделить их от кода. Если в фрагменте кода появляется более одного короткого комментария в одном фрагменте кода, то все они должны быть сдвинуты на одно и то же расстояние. Избегайте ассемблерного стиля пометки каждой строки кода комментарием в конце.
1 2 3 4 5 |
if (a == 2) { return TRUE; /* специальный случай */ } else { return isprime(a); /* работает только для нечётных а */ } |
Разделитель комментариев // начинает комментарий, который продолжается до новой строки. Он может комментировать как всю строку, так и только её часть. Однако его не следует использовать в нескольких строках подряд для текстовых комментариев.
1 2 3 4 5 6 |
if (foo > 1) { ... } else { return false; // Объясните здесь, почему false } |
Javadoc
Документирующие комментарии Javadoc описывают классы, интерфейсы, перечисления, конструкторы, методы и поля в Java. Каждый такой комментарий задаётся внутри разделителей комментариев /**…/, по одному комментарию на API. Эти комментарии должны размещаться непосредственно перед документируемым фрагментом (перед его объявлением).
1 2 3 4 |
/** * Класс Example обеспечивает ... */ public class Example { ... |
Что ж, правил немало. Однако всё приходит с опытом, и потихоньку даже можно перестать замечать, что вы их используете. В силу того, эти принципы начинают казаться чем-то базовым и неотъемлемым. Вместе с тем, это значительно упрощает восприятие кода. Потому всем рекомендую придерживаться конвенции по написанию кода на Java.
//