JavaRush /Java блог /Архив info.javarush /Типичные ошибки в Java-коде.
Sdu
17 уровень

Типичные ошибки в Java-коде.

Статья из группы Архив info.javarush
Данный материал содержит наиболее типичные ошибки, которые я видел в Java-коде людей работающих со мной. Статический анализ (мы используем qulice), по понятным причинам, не может выявить все подобные ошибки, вот почему я решил перечислить их здесь. Все перечисленные ошибки связаны с объектно-ориентированным программированием в целом и Java в частности.
Имена классов (Class Names)
Ваш класс должен быть абстракцией объекта реальной жизни без «валидаторов» ( «validators»), «контроллеров» («controllers»), «менеджеров» («managers») и т.д. Если имя Вашего класса заканчивается на «-er» - это плохой дизайн. И, конечно, вспомогательные классы, являющиеся анти-паттернами, вроде StringUtils, FileUtils, и IOUtils от Apache, прекрасные примеры ужасных дизайн-паттернов. Никогда не добавляйте суффиксы или префиксы для того, чтобы различать интерфейсы и классы. Для примера, все эти имена ужасны: IRecord, IfaceEmployee, или RecordInterface. Обычно, имя интерфейса это имя объекта реальной жизни, в то время как имя класса должно объяснить детали реализации. Если ничего конкретного о реализации сказать нельзя, подойдут имена «Default», «Simple», или что-либо подобное. Для примера: class SimpleUser implements User {}; class DefaultRecord implements Record {}; class Suffixed implements Name {}; class Validated implements Content {};
Имена методов (Method Names)
Методы могут или вернуть «что-то» или вернуть «void». Если метод возвращает что-то, тогда его имя должно объяснить, что будет возвращено. Для примера (не используйте префикс «get»): boolean isValid(String name); String content(); int ageOf(File file); Если возвращается «void», имя должно разъяснить что метод делает. Например: void save(File file); void process(Work work); void append(File file, String line); Существует только одно исключение из этого правила – тест методы JUnit. Они описаны ниже.
Имена тест методов (Test Method Names)
Имена методов в тестах JUnit должны быть построены как предложение английского языка без пробелов. Это легче объяснить на примере: /** * HttpRequest can return its content in Unicode. * @throws Exception If test fails */ public void returnsItsContentInUnicode() throws Exception { } Важно начинать первое предложение Вашего JavaDoc с имени класса, который Вы тестируете с последующим «can». Так, первое предложение всегда должно быть подобно фразе «кто-то может сделать что-то». Имя метода будет утверждать то же самое, но без предмета тестирования. Если я добавлю его в начало имени метода, то получу законченное английское предложение, как в приведенном выше примере: “HttpRequest returns its content in unicode”. Обратите внимание, имя тест метода не начинается с «can». С «can» начинаются только JavaDoc комментарии. Кроме того, имена методов не должны начинаться с глагола (От переводчика: по всей видимости, автор имеет в виду повелительное наклонение глагола). Хорошая практика, при объявлении тестового метода указывать, что выбрасывается исключение.
Имена переменных (Variable Names)
Избегайте составных имен переменных, типа timeOfDay, firstItem, или httpRequest. Я имею в виду и переменные класса, и переменные методов. Имя переменной должно быть достаточно длинным, чтобы избежать двусмысленности в своей области видимости, но, по возможности, не слишком длинным. Имя должно быть существительным в единственном или множественном числе. Для примера: List names; void sendThroughProxy(File file, Protocol proto); private File content; public HttpRequest request; Иногда могут появляться коллизии между параметрами конструктора и полями класса, если конструктор сохраняет входящие данные в созданный объект. В этом случае, я рекомендую создать аббревиатуру, удалив гласные. Пример: public class Message { private String recipient; public Message(String rcpt) { this.recipient = rcpt; } } В большинстве случаев, лучшим именем переменной будет имя соответствующего класса. Просто напишите его с маленькой буквы, и все будет хорошо: File file; User user; Branch branch; Тем не менее, никогда не делайте то же самое для примитивных типов, вроде Integer number или String string. Вы также можете использовать прилагательные, при наличии нескольких переменных с различными характеристиками. Например: String contact(String left, String right);
Конструкторы (Constructors)
Без исключения, должен быть только один конструктор, который сохраняет данные в переменные объекта. Все другие конструкторы должны вызывать этот с различными параметрами: public class Server { private String address; public Server(String uri) { this.address = uri; } public Server(URI uri) { this(uri.toString()); } }
Одноразовые переменные (One-time Variables)
Избегайте одноразовых переменных любой ценой. Под «одноразовыми» я имею в виду переменные используемые один раз. Как в этом примере: String name = "data.txt"; return new File(name); Переменная используется всего один раз, и код может быть упрощен до: return new File("data.txt"); Иногда, в очень редких случаях – в основном из-за лучшего форматирования – одноразовые переменные могут использоваться. Тем не менее, старайтесь избегать таких ситуаций.
Исключения (Exceptions).
Разумеется, Вы не должны никогда «проглатывать» исключения, они должны пробрасываться как можно выше. Исключения приватных методов, должны обрабатываться снаружи. Никогда не используйте исключения для управления потоком. Код указанный в примере неверен: int size; try { size = this.fileSize(); } catch (IOException ex) { size = 0; } Серьезно, что если IOException скажет что «диск полон», Вы будете считать, что размер файла равен нулю и продолжите?
Отступы (Indentation).
Для отступов, основное правило заключается в том, что скобка должна или заканчивать строку, или закрываться в этой же строке (для закрывающей скобки действует обратное правило). В примере ниже, код неверен, потому что первая скобка не закрыта в той же строке и после нее идут символы. У второй скобки та же проблема, так как есть символы перед ней, и нет открывающей скобки в текущей строке. final File file = new File(directory, "file.txt"); Правильные отступы должны выглядеть так: StringUtils.join( Arrays.asList( "first line", "second line", StringUtils.join( Arrays.asList("a", "b") ) ), "separator" ); Второе важное правило отступов гласит, что Вы должны разместить на одной линии как можно больше – в пределах 80 символов. Приведенный выше пример не является допустимым, так как он может быть уплотнен: StringUtils.join( Arrays.asList( "first line", "second line", StringUtils.join(Arrays.asList("a", "b")) ), "separator" );
Избыточные константы (Redundant Constants).
Константы класса, должны быть использованы, когда Вы хотите разделить доступ к информации между методами класса, и эта информация является характеристикой(!) Вашего класса. Не используйте константы в качестве замены строк или числовых литералов – очень плохая практика, это приводит к загрязнению кода. Константы (как и другие объекты ООП) должны иметь смысл в реальном мире. Какой смысл этих констант в реальном мире: class Document { private static final String D_LETTER = "D"; // bad practice private static final String EXTENSION = ".doc"; // good practice } Другая типичная ошибка – использовать константы в unit-тестах, чтобы избежать дублирования строки/числовых литералов в тестовых методах. Не делайте этого! Каждый тестовый метод должен работать со своим собственным набором входных значений. Используйте новые тексты и цифры в каждом новом тестовом методе. Тесты независимы. Так почему же они должны делить одни и те же входные константы?
Зацепление данных в тестах (Test Data Coupling).
Вот пример зацепления в тестовом методе: User user = new User("Jeff"); // maybe some other code here MatcherAssert.assertThat(user.name(), Matchers.equalTo("Jeff")); В последней строке мы сцепляем «Jeff» с этим же строковым литералом, указанным в первой строке. Если, несколькими месяцами позднее, кто-либо захочет изменить значение в третьей строке, он/она должен будет потратить дополнительное время на поиск, где еще "Jeff" используется в этом методе. Чтобы избежать этого зацепления данных, следует ввести переменную.
Комментарии (7)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
alexnjc Уровень 31
24 декабря 2014
В разных местах работы стили оформления кода могут немного расходиться. Но есть java code conventions, на который и нужно ориентироваться.
tempys Уровень 31
13 декабря 2014
ну как то название Validated больше запутает, чем название UserValidatedController.
EvIv Уровень 30
12 декабря 2014
Я бы еще добавил, что не нужно называть переменные и методы «русской латинкой», типа String imya; int vozrast;
От этого глаза кровоточат, такой стиль неприменим для сколь-нибудь серьезной работы, это нельзя показывать никому =)