Эта глава книги Effective Java собрала более общие советы по написанию кода на Java (и не только). Параграфов довольно много, поэтому я разбил свой сжатый пересказ на две части.
Item 45. Минимизируйте область видимости локальных переменных.
Это улучшает читабельность кода и уменьшает число потенциальных ошибок.
Прежде всего, по возможности объявлять локальную переменную надо там, где она впервые используется. Далее, почти все объявления локальных переменных должны содержать инициализацию. Исключение - когда инициализацию нужно поместить в
Отдельно следует отметить циклы. Цикл
Item 46. Предпочитайте
Опять же, это делает код более читабельным и уменьшает шансы ошибиться по невнимательности. Но есть и случаи, когда
Item 47. Знайте и применяйте библиотеки.
Изобретать колёса не имеет смысл, потому что:
Приведён хороший пример кривого колеса: самописная функция, возвращающая псевдослучайное число из интервала
Вместо такой функции следует использовать
Item 48. Избегайте
Типы
Item 49. Предпочитайте примитивы вместо объектных типов.
(здесь и далее под объектным типом подразумевается объектная обёртка примитива (boxed primitive))
Автобоксинг и автоанбоксинг (Java 1.5) размыл, но не стёр различия между ними. А различия таковы:
Item 50. Избегайте строк, если другие типы больше подходят.
Строки - не замена для других типов значений. Поступающая в программу информация, будь то чтение из файла, обмен по сети или ввод с клавиатуры, чаще всего приходит именно в текстовом виде и должна храниться в
Строки - не замена для
Строки - не замена для составных типов. Так делать плохо:
Строки не годятся для предоставления доступа к чему-либо. Имеется в виду то, что, например, строки нехорошо использовать в качестве ключей доступа к определённым данным в том случае, если клиентский код может нарушить целостность этих данных, предоставив неправильный или «чужой» ключ.
Далее спойлер (см. Item 47)
.
.
.
.
.
.
.
Три изъяна функции из Item 47:
Item 45. Минимизируйте область видимости локальных переменных.
Это улучшает читабельность кода и уменьшает число потенциальных ошибок.
Прежде всего, по возможности объявлять локальную переменную надо там, где она впервые используется. Далее, почти все объявления локальных переменных должны содержать инициализацию. Исключение - когда инициализацию нужно поместить в
try/catch
блок, а сама переменная нужна снаружи него.Отдельно следует отметить циклы. Цикл
for
предоставляет возможность объявлять переменные цикла (loop variables) доступными только для тела самого цикла, что делает его более предпочтительным, нежели циклы while
.Item 46. Предпочитайте
for-each
циклы вместо for
.Опять же, это делает код более читабельным и уменьшает шансы ошибиться по невнимательности. Но есть и случаи, когда
for-each
не подходит: фильтрация (когда нужно удалять элементы из коллекции, нужен явный итератор), трансформация (когда нужно заменять одни элементы списка или массива на другие, нужен явный итератор или переменная-индекс), параллельная итерация по нескольким коллекциям.Item 47. Знайте и применяйте библиотеки.
Изобретать колёса не имеет смысл, потому что:
- это лишняя трата времени;
- вряд ли получится лучше, чем уже написано ранее;
- библиотеки совершенствуются без вашего участия.
Приведён хороший пример кривого колеса: самописная функция, возвращающая псевдослучайное число из интервала
[0, n)
:static int random(int n) { return Math.abs(rnd.nextInt()) % n; }Функция выглядит нормально, но в ней скрыты целых три изъяна. Предлагается попробовать поискать их самостоятельно, однако два их них весьма нетривиальны (я-то их сам точно не нашёл бы). Эти недостатки перечислены в конце поста.
Вместо такой функции следует использовать
Random.nextInt(int)
, где этих проблем нет.Item 48. Избегайте
float
и double
, если нужны точные результаты.Типы
float
и double
представляют собой числа с плавающей запятой (floating point). Это означает, что они хранят не точное значение числа, а максимально близкое к нему приближение. Например, они не могут точно хранить числа 0.1
, 0.01
, 0.001
и т.д. Если задача требует точных результатов, лучше использовать BigDecimal
(хоть они и менее удобны и быстры, чем примитивы), либо сводить эту задачу к целым числам (например, считать деньги не в рублях, а копейках).Item 49. Предпочитайте примитивы вместо объектных типов.
(здесь и далее под объектным типом подразумевается объектная обёртка примитива (boxed primitive))
Автобоксинг и автоанбоксинг (Java 1.5) размыл, но не стёр различия между ними. А различия таковы:
- у объектных типов могут существовать разные экземпляры с одинаковыми значениями, что не позволяет сравнивать их между собой с помощью
==
, как примитивы; - объектные типы допускают дополнительное нефункциональное значение
null
; - примитивы экономичнее в плане производительности и использования памяти.
- при работе с коллекциями и другими параметризированными классами;
- при рефлексивном (reflective) вызове методов.
- если программа сравнивает объектные типы с помощью
==
, то сравниваются ссылки на объекты, что почти всегда не то, что вы хотите; - когда в выражении замешаны и примитивы, и объектные типы, выполняется unboxing последних;
- unboxing может вызвать
NullPointerException
.
Item 50. Избегайте строк, если другие типы больше подходят.
Строки - не замена для других типов значений. Поступающая в программу информация, будь то чтение из файла, обмен по сети или ввод с клавиатуры, чаще всего приходит именно в текстовом виде и должна храниться в
String
только если действительно представляет собой некоторый текст. Если же есть более подходящий тип для данных (числовые типы, boolean
, ...), нужно использовать его.Строки - не замена для
enum
-констант. Об этом было в Item 30.Строки - не замена для составных типов. Так делать плохо:
String compoundKey = className + "#" + i.next();
Для составных типов лучше писать составные классы.Строки не годятся для предоставления доступа к чему-либо. Имеется в виду то, что, например, строки нехорошо использовать в качестве ключей доступа к определённым данным в том случае, если клиентский код может нарушить целостность этих данных, предоставив неправильный или «чужой» ключ.
Далее спойлер (см. Item 47)
.
.
.
.
.
.
.
Три изъяна функции из Item 47:
- Если
rnd.nextInt()
выдастInteger.MIN_VALUE
, то функция вернёт отрицательное значение. - Если
n
- малая степень двойки, то последовательность генерируемых чисел довольное скоро начнёт повторять саму себя. - Если
n
- не степень двойки, то некоторые псевдослучайные числа будут генерироваться чаще других.
Комментариев нет:
Отправить комментарий