Эта страница содержит наиболее типичные ошибки, которые я вижу в коде Java людей, работающих со мной. Статический анализ (мы используем qulice, не можем поймать все ошибки по понятным причинам, и поэтому я решил перечислить их все здесь.
Дайте мне знать, если вы хотите увидеть что-то еще, добавленное здесь, и я буду рад вам помочь
Все перечисленные ошибки относятся к объектно-ориентированному программированию в целом и к Java в частности.
Имена классов
Прочитайте этот короткий «Что такое объект?» статья. Ваш класс должен быть абстракцией реальной сущности без «валидаторов», «контроллеров», «менеджеров» и т. Д. Если имя вашего класса заканчивается на «-er» — это плохой дизайн .
И, конечно, служебные классы являются анти-шаблонами, такими как StringUtils
, FileUtils
и IOUtils
от Apache. Выше приведены прекрасные примеры ужасных замыслов. Прочитайте этот пост: OOP Альтернатива служебным классам .
Конечно, никогда не добавляйте суффиксы или префиксы, чтобы различать интерфейсы и классы . Например, все эти имена ужасно неправильны: IRecord
, IfaceEmployee
или RecordInterface
. Обычно имя интерфейса — это имя реальной сущности, а имя класса должно объяснять детали его реализации. Если ничего не скажешь о реализации, назовите ее Default,
Simple
или что-то подобное. Например:
1
2
3
4
|
class SimpleUser implements User {}; class DefaultRecord implements Record {}; class Suffixed implements Name {}; class Validated implements Content {}; |
Имена методов
Методы могут либо возвращать что-то, либо возвращать void
. Если метод возвращает что-то, его имя должно объяснять, например, что он возвращает (никогда не используйте префикс get
):
1
2
3
|
boolean isValid(String name); String content(); int ageOf(File file); |
Если он возвращает void,
то его имя должно объяснять, что он делает . Например:
1
2
3
|
void save(File file); void process(Work work); void append(File file, String line); |
Существует только одно исключение из только что упомянутого правила — методы тестирования для JUnit. Они объяснены ниже.
Имена методов испытаний
Имена методов в тестах JUnit должны создаваться как английские предложения без пробелов. Это проще объяснить на примере:
1
2
3
4
5
6
|
/** * HttpRequest can return its content in Unicode. * @throws Exception If test fails */ public void returnsItsContentInUnicode() throws Exception { } |
Важно, чтобы первое предложение вашего JavaDoc начиналось с названия класса, который вы тестируете, а затем с помощью can
. Итак, ваше первое предложение всегда должно быть похоже на «кто-то может что-то сделать».
Имя метода будет точно таким же, но без субъекта. Если я добавлю тему в начале имени метода, я получу полное английское предложение, как в примере выше: «HttpRequest возвращает свое содержимое в юникоде».
Обратите внимание, что тестовый метод не начинается с can
Только комментарии JavaDoc начинаются с can. Кроме того, имена методов не должны начинаться с глагола.
Рекомендуется всегда объявлять методы тестирования как Exception
.
Имена переменных
Избегайте составных имен переменных, таких как timeOfDay
, firstItem
или httpRequest
. Я имею в виду как переменные класса, так и переменные внутри метода. Имя переменной должно быть достаточно длинным, чтобы избежать двусмысленности в его видимости, но не слишком длинным, если это возможно. Имя должно быть существительным в единственном или множественном числе или соответствующей аббревиатурой. Например:
1
2
3
4
|
List<String> names; void sendThroughProxy(File file, Protocol proto); private File content; public HttpRequest request; |
Иногда могут возникнуть коллизии между параметрами конструктора и свойствами класса, если конструктор сохраняет входящие данные в созданном объекте. В этом случае я рекомендую создавать сокращения, удаляя гласные (посмотрите, как USPS сокращает названия улиц ).
Другой пример:
1
2
3
4
5
6
|
public class Message { private String recipient; public Message(String rcpt) { this .recipient = rcpt; } } |
Во многих случаях лучший совет для имени переменной можно определить, прочитав ее имя класса. Просто напишите это маленьким письмом, и вам должно быть хорошо:
1
2
3
|
File file; User user; Branch branch; |
Однако никогда не делайте то же самое для примитивных типов, таких как Integer number
или String string
.
Вы также можете использовать прилагательное, когда есть несколько переменных с разными характеристиками. Например:
1
|
String contact(String left, String right); |
Конструкторы
Без исключений, должен быть только один конструктор, который хранит данные в переменных объекта. Все остальные конструкторы должны вызывать его с другими аргументами. Например:
1
2
3
4
5
6
7
8
9
|
public class Server { private String address; public Server(String uri) { this .address = uri; } public Server(URI uri) { this (uri.toString()); } } |
Одноразовые переменные
Избегайте одноразовых переменных любой ценой. Под «одноразовыми» я подразумеваю переменные, которые используются только один раз. Как в этом примере:
1
2
|
String name = "data.txt" ; return new File(name); |
Эта переменная используется только один раз, и код должен быть изменен на:
1
|
return new File( "data.txt" ); |
Иногда в очень редких случаях — в основном из-за лучшего форматирования — могут использоваться одноразовые переменные. Тем не менее, старайтесь избегать таких ситуаций любой ценой.
Исключения
Излишне говорить, что вы никогда не должны глотать исключения, а просто позволять им пузыриться как можно выше. Частные методы всегда должны позволять проверенным исключениям выходить.
Никогда не используйте исключения для управления потоком. Например, этот код неверен:
1
2
3
4
5
6
|
int size; try { size = this .fileSize(); } catch (IOException ex) { size = 0 ; } |
Серьезно, что, если это IOException
говорит «диск заполнен»? Будете ли вы по-прежнему считать, что размер файла равен нулю, и двигаться дальше?
вдавливание
Для отступа главное правило состоит в том, что скобка должна либо заканчивать линию, либо быть закрытой на той же самой строке (обратное правило применяется к закрывающей скобке). Например, следующее неверно, поскольку первая скобка не закрыта на одной строке и после нее есть символы. Вторая скобка также в беде, потому что перед ней есть символы, и она не открыта в той же строке:
1
2
|
final File file = new File(directory, "file.txt" ); |
Правильный отступ должен выглядеть так:
01
02
03
04
05
06
07
08
09
10
|
StringUtils.join( Arrays.asList( "first line" , "second line" , StringUtils.join( Arrays.asList( "a" , "b" ) ) ), "separator" ); |
Второе важное правило отступов гласит, что вы должны поместить как можно больше в одну строку — в пределах 80 символов. Приведенный выше пример недопустим, поскольку его можно сжать:
1
2
3
4
5
6
7
|
StringUtils.join( Arrays.asList( "first line" , "second line" , StringUtils.join(Arrays.asList( "a" , "b" )) ), "separator" ); |
Избыточные Константы
Константы класса следует использовать, когда вы хотите обмениваться информацией между методами класса, и эта информация является характеристикой (!) Вашего класса. Не используйте константы в качестве замены строковых или числовых литералов — очень плохая практика, которая приводит к загрязнению кода. Константы (как и любой объект в ООП) должны иметь значение в реальном мире. Какое значение имеют эти константы в реальном мире:
1
2
3
4
|
class Document { private static final String D_LETTER = "D" ; // bad practice private static final String EXTENSION = ".doc" ; // good practice } |
Другой типичной ошибкой является использование констант в модульных тестах, чтобы избежать дублирования строковых / числовых литералов в тестовых методах. Не делай этого! Каждый метод тестирования должен работать со своим набором входных значений.
Используйте новые тексты и цифры в каждом новом методе испытаний. Они независимы. Итак, почему они должны использовать одни и те же входные константы?
Тестирование связи данных
Это пример связи данных в тестовом методе:
1
2
3
|
User user = new User( "Jeff" ); // maybe some other code here MatcherAssert.assertThat(user.name(), Matchers.equalTo( "Jeff" )); |
В последней строке мы связываем "Jeff"
с тем же строковым литералом из первой строки. Если спустя несколько месяцев кто-то захочет изменить значение в третьей строке, ему / ей придется потратить дополнительное время на поиск, где еще "Jeff"
используется в том же методе.
Чтобы избежать этой связи данных, вы должны ввести переменную.
Похожие сообщения
Вы также можете найти эти сообщения интересными:
- Почему NULL это плохо?
- Объекты должны быть неизменными
- ООП Альтернатива служебным классам
- Избегайте конкатенации строк
- Простой Java SSH клиент
Ссылка: | Типичные ошибки в Java-коде от нашего партнера по JCG Егора Бугаенко в блоге About Programming . |