Краткое резюме лучших практик Java-кодирования

на основе стандартов кодирования Oracle, Google, Twitter и Spring Framework

Цель этой статьи - дать вам краткое изложение того, что можно и чего нельзя делать, другими словами, предпочитайте и избегайте на основе стандартов кодирования от таких технологических гигантов, как Oracle, Google, Twitter и Spring Framework.

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

Почему стандарты кодирования в первую очередь? Есть много веских причин, если вы Google это, и я оставлю вас со следующей иллюстрацией

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

Почти всегда вы присоединитесь к командам, работающим над существующим программным обеспечением, и есть большая вероятность того, что большинство авторов оставили или переключились на разные проекты, оставив вас в затруднении с частями кода, которые заставляют вас задавать вопросы человечеству.

Давайте погрузимся в лучшие практики из различных стандартов кодирования.

Исходный файл Java

Следующее считается наилучшей практикой, когда дело доходит до исходных файлов Java:

  • Длина исходного файла меньше 2000 строк кода
  • Исходный файл организован с комментарием к документации, объявлением пакета, за которым следует комментарий класса, импорт сгруппирован (static static), подпись класса / интерфейса и т. Д., Как показано ниже
пакет com.example.model;
/ **
 * Перспектива без реализации, которую могут прочитать разработчики
 * кто не обязательно может иметь исходный код под рукой
 *
 * @author x, y, z
 * @свидание
 * @version
 * @Авторские права
 *
 * /
import com.example.util.FileUtil;
/ *
 * Необязательный комментарий для конкретного класса
 *
 * /
открытый класс SomeClass {
  // Статические переменные в порядке видимости
  public static final Integer PUBLIC_COUNT = 1;
  static final Integer PROTECTED_COUNT = 1;
  приватное статическое окончание Integer PRIVATE_COUNT = 1;
  // Переменные экземпляра в порядке видимости
  публичное строковое имя;
  String postalCode;
  частный строковый адрес;
  // Конструктор и перегружен в последовательном порядке
  public SomeClass () {}
  public SomeClass (String name) {
    this.name = имя;
  }
  // Методы
  public String doSomethingUseful () {
    вернуть «Нечто полезное»;
  }
  // getters, setters, equals, hashCode и toString в конце
}

Именование

Имена классов и интерфейсов - CamelCase, поэтому рекомендуется использовать слово целиком и избегать сокращений / аббревиатур. Например класс Raster или класс ImageSprite

  • Пакет - имена com.deepspace над com.deepSpace или com.deep_space
  • Имена файлов имеют CamelCase и заканчиваются на .java, соответствующий имени класса. Существует один открытый класс на файл с каждым классом верхнего уровня в своем файле
  • Метод - имена должны быть глаголами в смешанном регистре, причем каждое внутреннее слово пишется с большой буквы, например, run (); или runFast ();
  • Константы - должны быть в верхнем регистре с «_», разделяя каждое слово, например, int MIN_WIDTH = 44; и int MAX_WIDTH = 99;
  • Переменная - имя, которое сообщает читателю программы, что представляет переменная, т. Е. Если вы сохраняете тестовую оценку, выберите оценку против var1. Держите имена переменных короткими, избегайте метаданных.
// Prefer () - имена переменных короткие и описывают, что они хранят
int schoolId;
int [] FilterSchoolIds;
int [] uniqueSchooldIds;
Карта  usersById;
Строковое значение;
// Avoid (x) - слишком подробное именование переменных
int schoolIdentificationNumber;
int [] userProvidedSchoolIds;
int [] schoolIdsAfterRemovingDuplicates;
Карта  idToUserMap;
String valueString;

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

Предпочитаю и избегаю

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

  • Отступы - используйте 2 или 4 пробела и оставайтесь последовательными
  • Длина строки - от 70 до 120 символов в зависимости от удобства чтения. Важно исключить необходимость горизонтальной прокрутки и ставить разрывы строк после запятой и оператора.

Методы - Вот список лучших практик

// Предпочитаем () Разрывы строк произвольны и разбиваются после запятой.
String downloadAnInternet (интернет-интернет, тюбики с трубками,
    Блогосферные блоги, объем трафика ) {
  tubes.download (интернет);
}
// Avoid (x) Трудно различать аргументы метода к телу метода
String downloadAnInternet (интернет-интернет, тюбики с трубками,
    Блогосферные блоги, Количество  пропускная способность) {
    tubes.download (интернет);
}
// Предпочитаем () Добавляем 8 (двойные из 2 или 4) пробелов для глубокого отступа
частное статическое синхронизированное horkingLongMethodName (int anArg,
        Object anotherArg, String YetAnotherArg,
        Object andStillAnother) {
  ...
}
// Предпочитаем () Простое сканирование и дополнительное пространство столбца.
public String скачать AnInternet (
    Интернет интернет,
    Трубы трубы,
    Блоги блогосферы,
    Amount  bandwidth) {
  tubes.download (интернет);
  ...
}
Юнит тест поймал бы это

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

// Избегаем (х) Не опускаем {}
если (условие)
  заявление;
// Избегаем (х)
если (х <0) отрицательный (х);
// Избегаем (х)
if (a == b && c == d) {
...
}
// Предпочитаем ()
if ((a == b) && (c == d)) {
...
}
// Предпочитаем ()
if (условие) {
  заявления;
} else if (условие) {
  заявления;
} else if (условие) {
  заявления;
}
// Избегаем (х)
если ((условие1 && условие2)
    || (условие3 && условие4)
    ||! (condition5 && condition6)) {// ПЛОХИЕ ОБОРОТЫ
    doSomethingAboutIt (); // СДЕЛАЙ ЭТУ ЛИНИЮ ПРОСТО ПРОПУСТИТЬ
}
// Предпочитаем ()
если ((условие1 && условие2)
        || (условие3 && условие4)
        ||! (условие 5 && условие 6)) {
    doSomethingAboutIt ();
}

Тернарный оператор - и ниже рекомендованные практики

альфа = (aLongBooleanExpression)? бета: гамма;
альфа = (aLongBooleanExpression)? бета
        гамма;
alpha = (aLongBooleanExpression)
        ? бета
        гамма;

Переключатель - когда дело доходит до переключения, лучше всего

  • Всегда иметь регистр по умолчанию даже без кода
  • Используйте / * проваливается * /, чтобы указать, что элемент управления переходит к следующему случаю
переключатель (условие) {
  кейс ABC:
    заявления;
  / * проваливается * /
  дело DEF:
    заявления;
    сломать;
  по умолчанию:
    заявления;
     сломать;
}

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

// Избегать (х) - не легко читать
выдает новое IllegalStateException («Не удалось обработать запрос» + request.getId ()
    + "для пользователя" + user.getId () + "query: '" + query.getText ()
    + "'");
// Prefer () - довольно легко читается
выдать новое IllegalStateException («Не удалось обработать»
    + "request" + request.getId ()
    + "для пользователя" + user.getId ()
    + "query: '" + query.getText () + "'");

Итераторы и потоки - потоки становятся все более распространенными, и иногда они могут быть очень сложными, поэтому важно сделать отступ для удобного чтения.

// Избегать (х) - не легко читать
Iterable  modules = ImmutableList.  builder (). Add (new LifecycleModule ())
    .add (новый AppLauncherModule ()). addAll (application.getModules ()). build ();
// Prefer () - довольно легко читается
Итерируемые  modules = ImmutableList.  builder ()
    .add (новый LifecycleModule ())
    .add (новый AppLauncherModule ())
    .addAll (application.getModules ())
    .build ();
Просто следуйте стандарту кодирования - любой действительно

Объявления и назначения. Рекомендуется одна декларация на строку, поскольку она поощряет комментарии, как показано ниже.

// Предпочитаем ()
международный уровень; // уровень отступа
int sizeMeter; // размер таблицы
// Избегать (х) в пользу выше
int level, sizeMeter;
// Предпочитать () - Включить модуль в имя или тип переменной
long pollIntervalMs;
int fileSizeGb;
Amount  fileSize;
// Избегаем (х) смешивания типов
int foo, fooarray [];
// Avoid (x) - не разделяйте запятой
Format.print (System.out, «error»), выход (1);
// Избегаем (х) множественного присваивания
fooBar.fChar = barFoo.lchar = 'c';
// Избегайте (x) встроенных назначений при попытке повысить производительность // или сохранить строку. Я виновен в этом :(
d = (a = b + c) + r;
// Предпочитаю () выше
a = b + c;
d = a + r;
// Предпочитаем ()
Строка [] args
// Избегаем (х)
Строковые аргументы []
// Предпочитаем () Длинное использование «L» вместо «l», чтобы избежать путаницы с 1
длительный тайм-аут = 3000000000L;
// Avoid (x) - трудно сказать, что последняя буква l, а не 1
длительное время ожидания = 3000000000 л;

Размещайте объявления только в начале блоков (блок - это код, заключенный в фигурные скобки {и}). Не ждите, чтобы объявить переменные до их первого использования; это может сбить с толку неосторожного программиста и затруднить переносимость кода в области видимости.

// Предпочитаем () объявлять в начале блока.
public void doSomething () {
  int whatIRepresent; // начало блока метода
  if (условие) {
    int someFlag; // начало блока if
    ...
  }
}

Также важно избегать местных деклараций, которые скрывают декларации более высоких уровней, и избегать путаницы, как показано ниже.

int count;
...
public void doSomething () {
  if (условие) {
    int count; // ИЗБЕЖАТЬ!
    ...
  }
  ...
}

Интервалы и разрывы строк - избегайте искушения сохранить 1-2 строки кода за счет читабельности. Вот все лучшие практики, когда дело доходит до пробелов и пустых строк (пробел имеет значение)

  • Одна (1) пустая строка между методами и разработчиками Spring рекомендует две (2) пустые строки после конструкторов, статического блока, полей и внутреннего класса
  • Операторы пробела, то есть используйте int foo = a + b + 1; через int foo = a + b + 1;
  • Отделите все двоичные операторы, кроме «.» От операндов, используя пробел
  • Открытая фигурная скобка «{» появляется в конце той же строки, что и оператор объявления или метод, а закрывающая фигурная скобка «}» сама по себе с отступом
// Prefer () - Пробел после «while» и перед «(»)
while (true) {
  ...
}
// Avoid (x) - в отличие от выше без пробела
while (true) {
  ...
}
// Prefer () - между "doSomething" и "(" нет пробела)
public void doSomething () {
  ...
}
// Avoid (x) - в отличие от пространства выше
public void doSomething () {
  ...
}
// Предпочитать () - добавить пробел после аргумента
public void doSomething (int a, int b) {
  ...
}
// Prefer () - Пробел между операндом и операторами (т.е. +, =)
а + = с + д;
a = (a + b) / (c * d);
while (d ++ = s ++) {
  п ++;
}

Документация и комментарии

Стоит отметить, что почти весь код претерпевает изменения на протяжении всей своей жизни, и будут случаи, когда вы или кто-либо пытаетесь выяснить, для чего предназначен сложный блок кода, метод или класс, если это не будет четко описано. Реальность почти всегда такова

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

Комментарии должны использоваться для обзора кода и предоставления дополнительной информации, которая не всегда доступна в самом коде. Давайте начнем. Есть два типа комментариев

Комментарии к реализации - предназначены для комментирования кода или комментария о конкретной реализации кода.

Комментарии к документации - предназначены для описания спецификации кода с точки зрения реализации, которую могут прочесть разработчики, которым необязательно иметь исходный код.

Частота комментариев иногда отражает низкое качество кода. Если вы чувствуете необходимость добавить комментарий, попробуйте переписать код, чтобы сделать его более понятным.

Типы реализации Комментарии

Существует четыре (4) типа комментариев к реализации, как показано ниже

  • Заблокировать комментарий - см. Пример ниже
  • Однострочный комментарий - когда комментарий не длиннее строки
  • Завершающие комментарии - очень короткий комментарий перенесен в правый конец
  • Комментарий конца строки - начинается комментарий, который продолжается до новой строки. Он может закомментировать полную строку или только частичную строку. Его не следует использовать в нескольких последовательных строках для текстовых комментариев; однако он может использоваться в нескольких последовательных строках для комментирования фрагментов кода.
// Заблокировать комментарий
/ *
 * Использование: Предоставляет описание файлов, методов, структур данных
 * и алгоритмы. Может использоваться в начале каждого файла и
 * перед каждым методом. Используется для длинных комментариев, которые не соответствуют
 * одна линия. 1 Пустая строка для продолжения после комментария блока.
 * /
// однострочный комментарий
if (условие) {
 / * Обработка условия. * /
  ...
}
// Завершающий комментарий
if (a == 2) {
 вернуть ИСТИНА; /* особый случай */
} еще {
 return isPrime (a); / * работает только для нечетных * *
}
// Конец строки комментария
if (foo> 1) {
  // сделать двойной щелчок
  ...
} еще {
  вернуть ложь; // Объясните, почему здесь.
}
// if (bar> 1) {
//
// // Делаем тройной флип
// ...
//}
// иначе
// return false;

Комментарии к документации (т.е. Javadoc)

Javadoc - это инструмент, который генерирует HTML-документацию для вашего java-кода, используя комментарии, которые начинаются с / ** и заканчиваются * / - см. Википедию для получения более подробной информации о том, как работает Javadoc, или просто читайте дальше.

Вот пример Javadoc

/ **
 * Возвращает объект изображения, который затем может быть нарисован на экране.
 * Аргумент url должен указывать абсолютный {@link URL}. Название
 * аргумент - это спецификатор, относящийся к аргументу URL.
 * 

 * Этот метод всегда возвращает сразу, независимо от того,  * изображение существует. Когда этот апплет пытается нарисовать изображение на  * экран, данные будут загружены. Графические примитивы  * что рисовать изображение будет постепенно рисовать на экране.  *  * @param url - абсолютный URL, указывающий базовое местоположение изображения  * @param name - расположение изображения относительно аргумента url.  * @ вернуть изображение по указанному URL  * @see Image  * /  общедоступное изображение getImage (URL-адрес, имя строки) {         пытаться {             return getImage (новый URL (URL, имя));         } catch (MalformedURLException e) {             вернуть ноль;         }  }

И приведенное выше приведет к HTML, как следует, когда Javadoc запускается против кода, который имеет выше

Смотрите здесь для более

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

@author => @author Raf
@code => {@code A  C}
@deprecated => @deprecated deprecation-message
@exception => @exception IOException выбрасывается, когда
@link => {@link package.class # метка участника}
@param => @param имя параметра
@return => Что возвращает метод
@see => @see "string" ИЛИ @see  
@since => Чтобы указать версию при добавлении общедоступного метода

Полный список и более подробное описание смотрите здесь

Стандарт кодирования Twitter запрещает использование тега @author

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

Ниже приведены примеры того, как вы могли бы написать комментарий к документации, который является проницательным, как описано в стандарте кодирования Twitter

// Плохо.
// - Документ ничего не говорит о том, что объявление метода не было.
// - Это «документ-заполнитель». Было бы пройти проверку стиля, но
никому не помогает
/ **
 * Разбивает строку.
 *
 * @param s Строка.
 * @return Список строк.
 * /
List  split (String s);
// Лучше.
// - Мы знаем, на что метод разбивается.
// - Еще какое-то неопределенное поведение.
/ **
 * Разбивает строку на пробел.
 *
 * @param s Строка для разделения. Строка {@code null} обрабатывается как пустая строка.
 * @return Список разделенных пробелами частей ввода.
 * /
List  split (String s);
// Отлично.
// - Охватывает еще один крайний случай.
/ **
 * Разбивает строку на пробел. Повторные пробельные символы
 * свернуты.
 *
 * @param s Строка для разделения. Строка {@code null} обрабатывается как пустая строка.
 * @return Список разделенных пробелами частей ввода.
 * /
List  split (String s);

При написании комментариев важно быть профессионалом.

// Избегаем (х)
// Я так ненавижу xml / soap, почему он не может сделать это для меня !?
пытаться {
  userId = Integer.parseInt (xml.getField ("id"));
} catch (NumberFormatException e) {
  ...
}
// Предпочитаем ()
// TODO (Джим): убрать проверку поля в библиотеке.
пытаться {
  userId = Integer.parseInt (xml.getField ("id"));
} catch (NumberFormatException e) {
  ...
}

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

И вот еще несколько моментов, о которых следует помнить

  • Избегайте импорта подстановочных знаков - как описано в стандартах кодирования Twitter, это делает источник класса менее понятным. Я работаю в команде, объединяющей пользователей Eclipse и IntelliJ, и обнаружил, что Eclipse удаляет импорт подстановочных знаков, а IntelliJ представляет его. Там, вероятно, есть возможность отключить его, просто хотел указать по умолчанию для двух.
  • Всегда используйте аннотацию @Override при переопределении
  • Поощряйте использование @Nullable, когда поле или метод возвращает ноль
  • Используйте специальные комментарии для будущей работы и не забудьте оставить ссылку на себя, чтобы другие знали, кому задать свой вопрос Y, вместо того, чтобы угадывать, удалять его или проверять вину, чтобы узнать, кто его добавил. Некоторые IDE, такие как Eclipse и IntelliJ, также помогают перечислить их для удобства доступа и для напоминания.
// FIXME (Raf): действенное сообщение описывает, что нужно сделать
// TODO (Raf): действенное сообщение описывает, что нужно сделать

Конечная игра заключается в написании кода, облегчающего жизнь будущим авторам и сопровождающим.

Конец игры

Другие соответствующие материалы для чтения

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

и еще один хороший список советов по написанию чистого кода