В этой статье перечислены некоторые типичные ошибки, которые я вижу в Java-коде моих коллег вокруг меня. Очевидно, что статический анализ кода (наша команда использует qulice) не сможет найти все проблемы, поэтому я перечисляю их здесь.
Если вы считаете, что чего-то не хватает, сообщите мне, и я буду рад это добавить.
Все перечисленные ниже ошибки в основном связаны с объектно-ориентированным программированием, особенно с ООП в Java.
Имя класса
Прочтите эту короткую статью «Что такое объекты». В реальной жизни класс должен быть абстрактной сущностью, а не «валидаторами», «контроллерами» и «менеджерами». Если имя вашего класса заканчивается на «эр» — это плохой дизайн.
Конечно, классы инструментов также являются антишаблонами, например, StringUtils, FileUtils и IOUtils Apache. Все вышеперечисленное — примеры плохого дизайна. Дополнительная литература: Альтернативы классам инструментов в ООП.
Конечно, не используйте префиксы или суффиксы, чтобы отличить классы от интерфейсов. Например, эти имена неверны: IRecord, IfaceEmployee или RecordInterface. Вообще говоря, имя интерфейса должно совпадать с именем реальной сущности, а имя класса должно описывать детали ее реализации. Если в реализации нет ничего особенного, вы можете назвать ее Default, Simple или что-то подобное. Например:
Скопируйте код кода следующим образом:
класс SimpleUser реализует User {};
класс DefaultRecord реализует Record {};
класс Suffixed реализует Name {};
класс Validated реализует Content {};
имя метода
Методы могут возвращать значения или void. Если метод возвращает значение, его имя должно, например, описывать то, что он возвращает (никогда не используйте префикс get):
Скопируйте код кода следующим образом:
логическое значение isValid (имя строки);
Строковое содержимое();
int ageOf (Файл-файл);
Если он возвращает void, его имя должно объяснять, что он делает. например:
Скопируйте код кода следующим образом:
void save (Файл-файл);
недействительный процесс (Работа, работа);
void add(Файл-файл, Строковая строка);
Из только что упомянутых правил есть только одно исключение — метод тестирования JUnit не учитывается. Об этом будет сказано ниже.
Название метода испытаний
В тестовых случаях JUnit имя метода должно быть английским оператором без пробелов. Будет понятнее на примере:
Скопируйте код кода следующим образом:
/**
* HttpRequest может возвращать свое содержимое в Юникоде.
* Исключение @throws, если тест не пройден
*/
public void returnItsContentInUnicode() выдает исключение {
}
Первое предложение в вашем JavaDoc должно начинаться с имени класса, который вы хотите протестировать, за которым следует слово can. Поэтому ваше первое предложение должно звучать примерно так: «Кто-то может что-то сделать».
Имя метода тоже такое же, только без темы. Если я добавлю тему в середину имени метода, я получу полное предложение, как в примере выше: «HttpRequest возвращает свое содержимое в Юникоде».
Обратите внимание, что название метода тестирования не начинается с буквы «банка». Только комментарии в JavaDoc начинаются с can. Кроме того, имена методов не должны начинаться с глагола.
На практике лучше всего объявить тестовый метод для выдачи исключения.
имя переменной
Избегайте объединения имен переменных, таких как timeOfDay, firstItem или httpRequest. Это справедливо для переменных класса и переменных внутри методов. Имена переменных должны быть достаточно длинными, чтобы избежать двусмысленности в пределах видимой области видимости, но, если возможно, не слишком длинными. Имя должно быть существительным в единственном или множественном числе или соответствующим сокращением. например:
Скопируйте код кода следующим образом:
Список имен <String>;
void sendThroughProxy (файл-файл, прототип протокола);
личное содержимое файла;
публичный запрос HttpRequest;
Иногда, если конструктор сохраняет входные параметры во вновь инициализированный объект, имена его параметров и атрибутов класса могут конфликтовать. В этом случае я предлагаю убрать гласные и использовать сокращения.
Пример:
Скопируйте код кода следующим образом:
Сообщение публичного класса {
получатель частной строки;
публичное сообщение (String rcpt) {
this.recipient = rcpt;
}
}
Во многих случаях вы можете определить, какое имя следует дать переменной, посмотрев на имя ее класса. Просто используйте его строчную форму, которая надежна следующим образом:
Скопируйте код кода следующим образом:
Файловый файл;
Пользователь Пользователь;
Филиал-филиал;
Однако никогда не следует делать это с примитивными типами, такими как целое число или строковая строка.
Если имеется несколько переменных разной природы, рассмотрите возможность использования прилагательных. например:
Скопируйте код кода следующим образом:
Строковый контакт (строка слева, строка справа);
Конструктор
Не обращая внимания на исключения, должен быть только один конструктор, используемый для хранения данных в переменных объекта. Другие конструкторы вызывают этот конструктор с другими параметрами. Например:
Скопируйте код кода следующим образом:
Сервер публичного класса {
частный строковый адрес;
общедоступный сервер (String uri) {
this.address = URI;
}
общедоступный сервер (URI uri) {
это(uri.toString());
}
}
одноразовая переменная
Одноразовых переменных следует избегать любой ценой. Под «одноразовым» я подразумеваю переменную, которая используется только один раз. Например, этот:
Скопируйте код кода следующим образом:
Имя строки = "data.txt";
вернуть новый файл (имя);
Вышеупомянутые переменные используются только один раз, поэтому этот код можно реструктурировать следующим образом:
Скопируйте код кода следующим образом:
вернуть новый файл("data.txt");
Иногда, в редких случаях — в основном для лучшего форматирования — можно использовать одноразовые переменные. Однако этого следует избегать, насколько это возможно.
аномальный
Излишне говорить, что вы никогда не должны проглатывать исключение самостоятельно, а должны передавать его как можно выше. Частные методы всегда должны выдавать проверенные исключения.
Не используйте исключения для управления потоком. Например, следующий код неверен:
Скопируйте код кода следующим образом:
внутренний размер;
пытаться {
размер = this.fileSize();
} catch (IOException ex) {
размер = 0;
}
Итак, что делать, если IOException выдает сообщение «Диск заполнен»? Будете ли вы по-прежнему думать, что размер файла равен 0, и продолжите обработку?
отступ
Что касается отступов, то основное правило заключается в том, что открывающая скобка либо заканчивается в конце строки, либо закрывается на этой же строке (для закрывающих скобок всё наоборот). Например, следующее неверно, поскольку первая открывающая скобка не закрывается в той же строке и после нее есть другие символы. Вторая скобка также проблематична, поскольку ей предшествуют символы, но соответствующая открывающая скобка не находится на той же строке:
Скопируйте код кода следующим образом:
окончательный файл файл = новый файл (каталог,
"файл.txt");
Правильный отступ должен быть таким:
Скопируйте код кода следующим образом:
StringUtils.join(
Arrays.asList(
«первая линия»,
«вторая линия»,
StringUtils.join(
Arrays.asList("a", "b")
)
),
"сепаратор"
);
Второе важное правило относительно отступов — стараться писать в строке как можно больше символов одновременно — верхний предел — 80 символов. Приведенный выше пример не удовлетворяет этому требованию, его также можно сократить:
Скопируйте код кода следующим образом:
StringUtils.join(
Arrays.asList(
«первая линия», «вторая линия»,
StringUtils.join(Arrays.asList("a", "b"))
),
"сепаратор"
);
избыточные константы
Константы класса следует использовать, когда вы хотите совместно использовать информацию внутри методов класса. Информация должна быть уникальной для вашего класса. Не используйте константы вместо строковых или числовых литералов — это очень плохая практика, которая загрязнит ваш код. Константы (как и любой объект в ООП) должны иметь свое значение в реальном мире. Давайте посмотрим, что означают эти константы в реальной жизни:
Скопируйте код кода следующим образом:
класс Документ {
Private static Final String D_LETTER = "D" // плохая практика;
Private static Final String EXTENSION = ".doc" // хорошая практика;
}
Другая распространенная ошибка — использование констант в модульных тестах, чтобы избежать избыточных строк или числовых литералов в методах тестирования. Не делайте этого! Каждый метод тестирования должен иметь свои уникальные входные значения.
Используйте новый текст или значения в каждом новом методе тестирования. Они независимы друг от друга. Так почему же они по-прежнему используют одни и те же входные константы?
Соединение тестовых данных
Вот пример связывания данных в методе тестирования:
Скопируйте код кода следующим образом:
Пользователь пользователя = новый пользователь («Джефф»);
// возможно здесь какой-то другой код
MatcherAssert.assertThat(user.name(), Matchers.equalTo("Джефф"));
В последней строке «Джефф» связан с тем же строковым литералом в первой строке. Если через несколько месяцев кто-то захочет изменить значение в третьей строке, то ему придется потратить время на то, чтобы выяснить, где в том же методе также используется «Джефф».
Чтобы этого избежать, лучше ввести переменную.