java отступы в коде
Java Code Style: как правильно оформлять код Java
Статья об именах переменных, классов и методов, скобках, комментариях, форматировании кода и других правилах хорошего тона, принятых в языке Javа.
В языке Java, как и во многих других языках программирования, есть неофициальные, но принятые сообществом разработчиков соглашения по оформлению кода. Давайте попробуем разобраться, что это такое, как работает и почему важно.
Зачем нужен единый стиль кода
Java Code Style — это рекомендации и соглашения о стиле кода, собранные вместе. Например:
Регламентируется множество вещей, связанных с оформлением исходного текста программ, и приводятся требования, которые необходимо учитывать. Почему возникли эти стандарты?
Причины, по которым разработчики пришли к таким соглашениям, логичны и просты:
Использование общепринятых соглашений по оформлению позволяет сделать код более аккуратным, избежать ошибок, связанных с разными стилями написания у людей, работающих над одним проектом.
Преподаватель Skillbox. Пишет про Java, учит Go. Помнит рассвет PHP и как «грабить корованы».
Форматирование на практике
Стиль не играет роли для компьютера, но важен для чтения кода человеком. Наше зрение устроено так, что сперва получает и анализирует образы, а только затем мы вдаёмся в детали. А если блоки исходного текста унифицированы, разработчик понимает, что перед ним за конструкция, даже не вникая в сам код.
Рекомендации к стилю кода
Правила языка Java
Правила Java библиотек
Существуют соглашения, по поводу использования Java библиотек и инструментов для Android. В некоторых случаях соглашения могут быть изменены, например, в таких как использование старого кода, который, возможно, использует неодобренный паттерн или библиотеку.
Правила Java стиля
Программы гораздо проще поддерживать, когда все файлы имеют согласованный стиль. Мы следуем стандартному стилю программирования на Java, определенному Sun в их Code Conventions for the Java Programming Language, с несколькими исключениями и дополнениями. Данное руководство по стилю является подробным и всесторонним, а также широко используется Java сообществом.
Правила языка Java
Не игнорируйте исключения
Возможно, вам захочется написать код, который игнорирует исключения, например:
Не перехватывайте обобщенные исключения
Иногда бывает заманчиво полениться с обработкой исключений и написать что-то вроде этого:
Вам не следует так делать. Суть в том, что возможно появление исключения, которого вы не ожидали и, в итоге, ошибка будет отлавливаться на уровне приложения. То есть, если кто-то добавит новый тип исключения, то компилятор не сможет вам помочь понять, что это другая ошибка.
Существуют редкие исключения из этого правила: определенный тестовый код, или код верхнего уровня, где вы хотите перехватывать все типы ошибок (для того, чтобы предотвратить их отображение в пользовательском интерфейсе, или чтобы продолжить какую-то пакетную задачу).
Финализаторы
Что это: Финализаторы — это способ запускать программный код перед тем как объект собирается сборщиком мусора.
За: могут быть полезны при очистке, в особенности внешних ресурсов.
Против: нет никаких гарантий того, когда будет вызван финализатор, и, вообще, будет ли он вызван.
Решение: Мы не используем финализаторы. В большинстве случаев, всё то, что вам нужно от финализатора, вы сможете сделать при помощи обработки исключений. Если вам действительно нужен финализатор, то объявите метод close() и задокументируйте, когда он точно будет вызываться.
Импорты
Групповой символ в импортах
Что это: Когда вы хотите использовать класс Bar из пакета foo, то есть два способа сделать это:
За #1: Потенциально уменьшает количество возможных операторов импорта.
За #2: Делает явным то, какой класс на самом деле используется. Делает код более удобочитаемым для тех, кто его поддерживает.
Решение: Используйте стиль #2 для импорта любого Android кода. Явное исключение делается для стандартных библиотек (java.util.*, java.io.*, и т.п) и для кода модульного тестирования (junit.framework.*).
Комментарии/Javadoc
Каждый файл должен иметь объявление об авторских правах в самом начале. Далее идут объявления операторов package и import, причем каждый блок разделяется пустой строкой. За ними следуют объявления класса или интерфейса. Опишите, что делает класс в Javadoc-комментариях.
Каждый класс и нетривиальный public метод должен содержать Javadoc, по крайней мере с одной фразой, описывающей что он делает. Фраза должна начинаться с описательного глагола 3-го лица. Примеры:
Вам не нужно описывать Javadoc для тривиальных get и set методов, таких как setFoo(), если ваш Javadoc говорит только «sets Foo». Если метод делает что-то более сложное (например, соблюдение неких ограничений, или если его действия имеют важный эффект вне его самого), тогда его обязательно нужно задокументировать. И если это не просто объяснение того, что означает Foo, то вам также следует его задокументировать.
Вообще, любой метод, который вы написали получает пользу от Javadoc, неважно public он или нет. Public методы являются частью API, и поэтому они требуют описания в Javadoc.
Для написания Javadoc’ов вам следует придерживаться Sun Javadoc conventions.
Короткие методы
Методы должны быть небольшими и решающими конкретную задачу настолько, насколько это возможно. Однако, понятно, что иногда большие методы бывают целесообразны, так что нет строгого ограничения на длину метода. Если метод превышает 40 строк, то вам, возможно, стоит подумать о том, можно ли его разбить на части, не нарушив структуры программы.
Локальные переменные
Область видимости локальных переменных должна сводиться к минимуму. Делая это, вы улучшаете читаемость и поддерживаемость кода, а также уменьшаете вероятность ошибок. Каждая переменная должна объявляться в самом глубоком блоке, который окружает все возможные места использования переменной.
Локальные переменные должны объявляться в том месте, где впервые необходимо её использовать. Почти каждая локальная переменная нуждается в инициализаторе. Если вы еще не знаете, как точно инициализировать переменную, то вам следует отложить её объявление, пока вы это не узнаете.
Существует одно исключение, касательно блока try-catch. Если переменная инициализируется при помощи оператора return метода, который выбрасывает проверяемое исключение, то она должна инициализироваться в блоке try. Если же переменная должна использоваться вне блока try, тогда она объявляется перед ним, неважно, знаете ли вы как её точно нужно инициализировать:
Но даже этот случай можно обойти при помощи инкапсуляции блока try-catch в методе.
Переменные в циклах должны объявляться внутри самого оператора, если только нет непреодолимой причины этого не делать.
Импорты
Отступы
мы используем 4 пробела для блоков. Мы никогда не используем табуляцию. Мы используем 8 пробелов для переноса строк, включая вызовы функций и присваивания, например правильно так:
Названия полей
Фигурные скобки
Для открывающих фигурные скобок не выделяется отдельная строка, они находятся в той же строке, что и код перед ними:
Мы требуем фигурные скобки для оператора условия. Исключением является, когда оператор условия и его тело помещаются в одну строку. То есть можно писать так:
Длина строки
Каждая строка текста в коде должна быть не длиннее 100 символов.
Исключение: если комментарий содержит пример команд, или URL (удобнее использовать copy/paste).
Исключение: строки импорта могут быть длиннее 100 символов, так как люди редко на них смотрят. Также это упрощает написание инструментов.
Сокращения в именах
Рассматривайте сокращения и аббревиатуры как слова. Имена более удобочитаемы:
Хорошо | Плохо |
XmlHttpRequest | XMLHTTPRequest |
getCustomerId | getCustomerID |
Этот стиль также применяется, когда сокращение и аббревиатура — это полное имя:
Хорошо | Плохо |
class Html | class HTML |
String url; | String URL; |
long id; | long ID; |
Стиль TODO
Используйте комментарии TODO для кода, который является временным, краткосрочным, или хорошим, но не идеальным. Комментарий должен включать в себя «TODO:», например:
Если ваш комментарий имеет вид «В будущем сделать что-то», то убедитесь, что он включает в себя конкретную дату (1 января 2011 года), или конкретное событие «Удалить после выхода версии 2.1».
Согласованность
Если вы изменяете код, то потратьте минуту на то, чтобы посмотреть на код вокруг вас и определить его стиль. Если в нем используются пробелы, то и вам следует их использовать. Если комментарии содержат небольшой набор звездочек, то и вам следует их использовать.
Весь смысл рекомендаций к стилю кода в создании общей лексики, чтобы люди концентрировались на том, что они говорят, вместо того как они говорят. Мы представляем глобальные правила стиля, чтобы люди знали эту лексику. Но локальный стиль также важен. Если код, который вы добавляете в файл выглядит резко отличным от того, что был, то это выбросит будущего читателя из его ритма и будет мешать ему понимать структуру. Старайтесь избегать этого.
Nikolay995 / JavaCodeStyle.md
Файлы с исходным кодом
Файлы с исходным кодом хранятся в кодировке UTF-8.
Символы пустого места
Кроме символов перевода строки, только ASCII-пробел (0x20) встречается в файлах. Это означает:
Для любого символа, который имеет специальную escape-последовательность (b, \t, \n, \f, \r, «, ‘ и \), эта последовательность используется вместо соответствующего octal (например \012) или Unicode-символа (например \u000a).
Для остальных не-ASCII символов, используется или сам Unicode-символ (например ∞) или соответствующий Unicode escape-символ (например \u221e). Выбор символа зависит только о того, насколько легко код с ним читать и понимать, хотя Unicode escape-символы вне строковых литералов и комментариев вставлять не рекомендуется.
Совет: в случае использования Unicode escape-символа, и иногда даже когда используется сам Unicode символ, поясняющие комментарии могут быть полезны.
Пример | Комментарии |
---|---|
String unitAbbrev = «μs»; | Лучший вариант: все ясно даже без комментария |
String unitAbbrev = «\u03bcs»; // «μs» | Разрешается, но нет причины так делать |
String unitAbbrev = «\u03bcs»; // Greek letter mu, «s» | Разрешается, но странно выглядит и неустойчиво к ошибкам |
String unitAbbrev = «\u03bcs»; | Плохо: читатель не поймет, что это такое |
return ‘\ufeff’ + content; // byte order mark | Хорошо: используется escape-символ для непечатных символов, и есть коммент |
Совет: не делайте ваш код менее читаемым просто из боязни, что какая-либо программа не сможет обработать не-ASCII символы верно. Если такое случается, значит программа работает неправильно и должна быть починена.
Файл с исходным кодом состоит из:
Секции разделяются одной пустой линией.
Имя пакета не разделяется переносом строки. Заданная нами длина строки не распространяется на строку с именем пакета.
Использование wildcard и static импортов не рекомендуется. Исключение: если ситуация оправдана, и все испортируемые методы и константы близки по смыслу к классу в данном файле.
Импорт не разделяется переносом строки. Заданная нами длина строки не распространяется на строку с импортом класса.
Нет специальных правил на порядок импортов. Придерживаемся стиля, заданного по-умолчанию в используемой всеми IDE.
Каждый класс верхнего уровня находится в отдельном файле с его именем.
Порядок расположения членов класса
Члены классы располагаются в таком порядке:
Не разрываем последовательность перегруженных методов
Если у класса есть несколько конструкторов или методов с одним и тем же именем, они располагаются друг за другом, без включения других полей/методов
Ставим скобки, даже если это необязательно
Непустые блоки: стиль K & R
Скобки ставятся в соответствии со стилем Кернигана и Ричи (Египетские скобки) для непустых блоков:
Исключения делаются для Enum-классов.
Пустые блоки не укорачиваем
Ставим перевод строки и комментарий, даже если тело блока пустое:
Отступы слева для блоков
Каждый раз, когда мы открываем новый блок, отступ увеличивается на 2 пробела. Когда блок заканчивается, отступ возвращается до прежнего значения. Отступ применяется и для комментариев в блоке.
Одно выражение на строку
Каждое выражение или оператор заканчивается переводом строки.
Длина строки в коде имеет лимит в 120 символов. Кроме исключений, любая строка больше лимита должна быть разбита на 2 строки, как описано в разделе Перенос строки.
При переносе строк, каждая перенесенная строка после самой первой отступает слева на 8 пробелов от начальной строки. В общем случае, отступ для 2 перенесенных строк будет одинаковым только если начинаются с синтаксически параллельных конструкций.
Вертикальное пустое место
Одна пустая строка стоит:
Несколько пустых строк подряд разрешается, но не обязательно.
Горизонтальное пустое место
Одиночный ASCII-пробел встречается в следующих местах (помимо требования синтаксиса языка, литералов, комментов и javadoc):
Правила относятся к пробелам внутри строки, а не отступам (оговариваются в другом разделе).
Горизонтальное выравнивание не используется
Выравнивание может улучшить читаемость, но создает проблемы для дальнейшей поддержки. Допустим, последующее изменение затрагивает всего 1 строку. Часто такое изменение сбивает выравнивание, что выглядит уже не так хорошо. Но чаще разработчик стремится поддержать порядок выравнивания и меняет оступы в других строках, инициируя каскадную серию форматирований. Это однострочное изменение теперь имеет «радиус поражения». Это бесполезная работа, также это ухудшает читаемость истории версий, замедляет ревьюеров и затрудняет разрешение merge-конфликтов.
После каждой запятой после определения Enum-константы нужен перевод строки. Дополнительно допускается пустая строка после этого. Пример:
Enum-классы в остальном подчиняются общим правилам оформления классов.
В каждой строке определяется только одна переменная
Каждое определение (поле или локальная переменная) состоит только из одной переменной: определения вида int a, b; не используются.
Переменные определяются по мере надобности
Локальные переменные не обязательно должны определятся в начале блока или метода. Вместо этого, он определяются как можно ближе к месту их первого использования, чтобы уменьшить область действия переменной. Локальные переменные как правило сразу инициализируются.
Квадратные скобки ставятся рядом с типом, а не самой переменной: String[] args, но не String args[].
Внутри скобок в switch-блоке располагаются одна или несколько групп операторов. Каждая группа содержит одну или несколько меток (например FOO: или default:), за которой следуют операторы.
Как и с другими блоками, оступ для содержимого составляет +2 пробела. После метки стоит перевод строки, и отступ снова увеличивается на +2, как в случае с открытием нового блока. Следующая метка находится на предыдущем уровне, как будто блок закрылся.
Провалы в следующие метки: не используются
Исключения делается только для пустых меток (пример выше с case 1:). Для каждого switch должна быть default-метка, даже если она не содержит кода.
Аннотации, применяемые к классу, методу или конструктору ставятся сразу после блока документации, и находятся на отдельной строке (по одной аннотации на строке). Отступ слева после аннотации не увеличивается. Пример:
Нет специальных правил для форматирования аннтотаций на параметрах, локальных переменных, типах.
Модификаторы классов и методов ставятся в порядке, рекомендованном Java Language Specification:
public protected private abstract default static final transient volatile synchronized native strictfp
Числовые литералы типа long используют большую букву L, никогда не используется нижний регистр (чтобы избежать путаницы с цифрой 1). Например, надо писать 3000000000L вместо 3000000000l.
Правила для всех идентификаторов
Имена пакетов пишутся в нижнем регистре, слова просто последовательно конкатенируются друг с другом (без нижних подчеркиваний). Например, com.example.deepspace, а не com.example.deepSpace или com.example.deep_space.
Имена классов пишутся в UpperCamelCase.
Нет специальных правил для именования аннотаций.
Тестовые классы начинаются с имени класса, который они тестируют, и заканчиваются на Test. Например, HashTest или HashIntegrationTest.
Имена методов пишутся в lowerCamelCase.
Имена констант используют CONSTANT_CASE: все буквы в верхнем регистре, слова отделяются нижним подчеркиванием. Но что есть константа?
Каждая константа является static final полем, но не все static final поля являются константами. Прежде чем именовать переменную константой, подумайте реально ли она является ей. Например, если видимое состояние экземпляра обьекта может измениться, это точно не константа. Просто мысли о том, что объект не будет меняться в процессе работы, не достаточно. Примеры:
Имена неконстантных полей
Имена параметров пишутся в lowerCamelCase. Односимвольных имен параметров в публичных методах следует избегать.
Имена локальных переменных
Имена локальных переменных пишутся в lowerCamelCase. Даже когда они final и immutable, локальные переменные не надо путать с константами, и именовать их как константы.
Имена переменных типов
Каждая переменная типа именуется одним из 2 способов:
Определение Camel Case
Иногда есть несколько способов конвертировать английскую фразу в camel case, например для аббревиатур или необычных имен типа «IPv6» или «iOS». Чтобы имя было предсказуемо, предлагается такая схема.
Примите во внимание, что регистр букв в оригинальных словах не принимается во внимание. Примеры:
Оригинальная фраза | Правильно | Неправильно |
---|---|---|
«XML HTTP request» | XmlHttpRequest | XMLHTTPRequest |
«new customer ID» | newCustomerId | newCustomerID |
«inner stopwatch» | innerStopwatch | innerStopWatch |
«supports IPv6 on iOS?» | supportsIpv6OnIos | supportsIPv6OnIOS |
«YouTube importer» | YouTubeImporter | YoutubeImporter |
Примечание: некоторые слова имеют несколько написаний через дефис в английском языке, например оба «nonempty» и «non-empty» верны. Таким образом, имена методов checkNonempty и checkNonEmpty тоже оба верны.
@Override: всегда используется
Метод всегда помечается аннотацией @Override, если это верно с точки зрения языка. Это включает в себя:
Исключение: @Override можно опустить, если метод родителя обьявлен как @Deprecated.
Перехватываемые исключения: не игнорируются
Кроме случая, описываемого ниже, очень редко является корректным ничего не делать в ответ на перехваченное исключение (типовые способы: логгировать его, если же обьявлено «невозможным», выбросить заново как AssertionError).
Когда реально ничего не надо делать в catch-блоке, причина указывается в поясняющем комментарии:
Исключение: в тестах, перехваченное исключение может игнорироваться без комментария, если имя переменной начинается с expected. Это часто встречается, когда надо убедиться, что тестируемый код бросает исключение нужного типа, поэтому комментарий излишен.
Статические члены класса: указываются через имя класса
Когда нужно указать или сослаться на статическое поле или метод класса, оно определяется с именем класса, а не с ссылкой на обьект или выражение, возвращающее объект типа этого класса.
Finalizers: не используются
Совет: не делайте этого. Если позарез надо, сначала прочитайте и поймите Effective Java Item 7, «Avoid Finalizers», а после этого не делайте этого.
Common information
Указания по редактированию данного документа¶
На редактирование следует открывать минимальную по размерам часть документа (нажимать на соответствующую иконку с карандашом).
Предложения по изменению документа следует обрамлять тэгами
Соглашения об именах¶
Имена должны быть осмысленными словами (или словосочетаниями в значении соответствующей части речи) английского языка.
Имена пакетов и подпакетов — существительные в единственном числе в нижнем регистре, слова разделяются подчёркиваниями ( program_installer ).
Имена классов и интерфейсов — существительные или словосочетания в значении существительных: в нижнем регистре, первые буквы слов — в верхнем регистре, разделители слов не используются ( ClientInfo ); имена классов-исключений заканчиваются на Exception ( InvalidUserException ).
Рекомендуется для классов-наследников использовать имена, в которых содержится имя суперкласса ( ModalDialog extends Dialog ); исключение — имена классов-наследников, из которых следует, что данный класс наследует суперкласс ( Triangle extends Figure ).
Имена полей̆ и локальных переменных — существительные в нижнем регистре, первые буквы слов начиная со второго — в верхнем регистре, разделители слов не используются ( fileSize ).
Имена полей и локальных переменных не должны вводить в заблуждение относительно их типов. Пример (!) НЕПРАВИЛЬНОГО (!) именования переменной: String currentPlayer = player.getName();
Имена методов — глаголы в нижнем регистре (либо словосочетания, отражающие действия), первые буквы слов начиная со второго — в верхнем регистре, разделители слов не используются ( removeFile ).
В названии методов нужно использовать глаголы, которые как можно более точно и полно описывают то, что выполняет метод.
Имена методов, выполняющих преобразование к другому типу данных, должны начинаться на to ( toString ).
Имена методов, которые создают и возвращают созданный объект, должны начинаться с create ( createRecord ).
Имена методов, инициализирующие поля класса или элементы графического интерфейса, должны начинаться с init ( initWindow ) и использоваться только в конструкторе класса. Таких методов следует избегать.
Имена static final переменных — существительные или словосочетания в верхнем регистре, слова разделены подчёркиваниями ( INVALID_RECORD_COLOR ).
Требования к отдельным деталям реализации¶
Тело метода анонимного класса должно состоять только из вызова метода объемлющего класса.
Все элементы программы должны иметь минимально возможную область видимости.
Аргументы, передаваемые в методы, не должны изменяться внутри этих методов.
Запрещается использование статических полей и методов при наличии возможности достичь результата другими средствами. Если метод не использует данные класса, то его следует сделать статическим, но только если не возможно достичь результата другим путём.
Запрещается использование методов, выполняющих две или более самостоятельные операции. Каждый такой метод подлежит разбиению на более мелкие.
Запрещается секционирование методов. Секционирование означает, что метод можно разделить на несколько.
Методы, изменяющие состояние объекта, не должны возвращать статус этой операции (например, метод insert(object) должен выполнять только операцию вставки и не должен возвращать статус этой операции).
Не рекомендуется возвращать какие-либо значения из методов, изменяющих состояния объекта.
Запрещается собственная реализация средств, имеющих аналоги в стандартной библиотеке Java API. Во всех случаях, когда возможно использование библиотечных классов Java API, они должны быть использованы.
Рекомендуется использование сторонних библиотек в случаях, когда это возможно.
Запрещается посимвольная обработка строковых данных в стиле языка C. Вместо этого необходимо использовать средства стандартной библиотеки.
Запрещается использование средств библиотек, обозначенных в документации как deprecated (устаревшие).
Нежелательно использование средств библиотек, обозначенных в документации как legacy (для обратной совместимости).
Запрещается импортирование всех элементов, содержащихся в пакете (import *)/vxvv
Требования по оформлению исходного текста программы¶
Исходный текст каждого класса программы должен быть размещён в отдельном файле (кроме вложенных классов).
Пустые строки внутри класса должны быть только между методами. Порядок следования элементов класса следующий: поля, конструкторы, методы. Пример:
Программы должны быть выровнены в соответствии со стилем Кёрнигана и Ричи.
Величина отступа всюду должна быть 4 пробела. Запрещается использовать символ табуляции.
Все операторы линейной части программы должны иметь один и тот же отступ. Отступ увеличивается для объявлений вложенных классов, полей и методов классов, тел методов, субоператоров (в т. ч. для всех операторов блока, образующего субоператор).
При использовании множественного ветвления обязательно следует размещать конструкции else if строго друг под другом без дополнительных отступов.
Точка с запятой, завершающая пустой оператор, должна размещаться на отдельной строке.
Не допускается использование строк, длина которых больше 95 символов. Не вмещающиеся части строки переносятся на следующие строки с отступом относительно предыдущей строки. Рекомендуется использовать отступ вдвое больше определённого для программы. Перенос строк, содержащих объявление метода, допускается осуществлять без отступа.
Запрещается перенос аргументов метода в стиле WIN32, т. е. когда каждый аргумент располагается на новой строке. Пример:
Запрещается размещение нескольких операторов в одной строке, кроме случаев, когда это не ухудшает удобочитаемости программы.
Рекомендуется использование пробелов для отбивок отдельных лексем в программе. Способ расстановки пробелов в этом случае должен соответствовать полиграфическим правилам.
Многострочный документационный комментарий выравнивается следующим образом: первая и последняя строки содержать только символы /** и */ (или **/) соответственно. Все промежуточные строки начинаются со звёздочки, за которой следует текст комментария.
Требования по документированию программы¶
Обязательными являются документационные комментарии для всех классов, полей и методов.
Если смысл хотя бы одного из принимаемых или возвращаемых методом значений или выбрасываемых исключений не является интуитивно понятным, то соответствующий документационный комментарий должен содержать описание всех указанных элементов.
В случае использования меток в операторах break и continue обязательно наличие комментария в строке, содержащей один из указанных операторов.
Комментарии не должны содержать орфографических и пунктуационных ошибок.
В случае, если комментарий к полю класса начинается с существительного, перед ним должен стоять артикль The.
Неочевидные фрагменты кода, нацеленные на исправление отдельных ситуаций (являющиеся Hack’ом), нужно выделять в отдельные функции и подробно комментировать цель их использования. Если такая строчка всего одна, то можно использовать комментарий посреди кода.