Java. Эффективное программирование, 2-е издание

Java. Эффективное программирование, 2-е издание
Автор: Блох Джошуа
Год: 2014
ISBN: 978-5-85582-348-6
Страниц: 461
Язык: Русский
Формат: PDF
Размер: 25 Мб

Download

В книге Java. Эффективное программирование содержится пятьдесят семь правил. Предлагаются решения задач программирования, с которыми часто приходится сталкиваться разработчикам. Джошуа Блох детально описывает приемы, которые используют эксперты, создававшие платформу Java. Объясняет, что нужно делать, а что делать не следует, для получения надежного, эффективного и понятного программного кода.
Каждое правило представлено в виде лаконичного законченного эссе. Дается описание проблемы, примеры программного кода, случаи из практики самого автора, Джошуа Блоха. В эссе входят специальные рекомендации, обсуждение различных аспектов языка Java. В качестве иллюстрации выбраны лучшие примеры программ. Дана оценка распространенных идиом языка Java, шаблоны разработки, полезные советы и методики.

+

Технология, известная как перечислимый шаблон int, обладает многими недостатками. Она не обеспечивает безопасность типов и не очень удобна. Компилятор не будет жаловаться, если вы передадите яблоко методу, который ожидает апельсин, сравните яблоки с апельсинами оператором == или хуже:

// Вкусный цитрусовый приправлен яблочным соусом!

int i = (APPLE.FUJI – ORANGE_TEMPLE) / APPLE.PIPPIN;

Обратите внимание, что название каждой константы яблока содержит префикс APPLE__ и что название каждой константы апельсина содержит 0RANGE_. Это потому, что Java не предоставляет пространства имен для перечислимых групп int. Префиксы препятствуют совпадению имен, если две перечислимые группы int будут иметь константы с одинаковыми названиями.

Программы, использующие перечислимый шаблон int, довольно «хрупки». Поскольку перечислимые шаблоны int являются константами на время компиляции, они компилируются в клиенты, которые их используют. Если int связанный с перечислимой константой изменяется, то его клиенты должны быть заново скомпилированы. Если этого не сделать, то запускаться они будут, но их поведение будет непредсказуемо.

Нет легкого способа перевести перечислимые константы в печатаемые строки. Если вы напечатаете такую константу или отобразите ее в отладчике, все, что вы увидите, — это число, что не очень поможет. Нет надежного способа выполнить итерацию перечислимых констант в группе или даже получить размер перечислимой группы int.

Вы можете столкнуться с вариантом шаблона, в котором константы String используются вместо констант int. Этот вариант, известный как перечислимый шаблон String, желательно еще меньше использовать.

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

К счастью, в версии 1.5 язык дает нам альтернативу, которая помогает избежать недостатков перечислимых шаблонов int и string и предлагает ряд дополнительных преимуществ. Это перечислимые типы [JLS, 8.9]. Вот как они выглядят в простейшей форме:

public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }

public enum Orange { NAVEL, TEMPLE, BLOOD }

При поверхностном взгляде может показаться, что перечислимые типы похожи на свои аналоги в других языках, таких как С, C++ , и C# , но это сходство обманчиво. Перечислимые типы Java — это полноценные классы, обладающие большими возможностями, чем их аналоги в других языках, где перечислимые типы являются по сути значениями int.

Основная идея перечислимых типов в Java проста: они являются классами, которые экспортируют один экземпляр каждой перечислимой константы, используя открытое статическое завершенное поле. Перечислимые типы являются абсолютно завершенными благодаря тому, что у них нет конструкторов. Клиенты не могут ни создавать экземпляры перечислимых типов, ни расширять их, не создаются никакие другие экземпляры, кроме декларированных перечислимых констант. Другими словами, перечислимые типы подвергаются контролю создания экземпляров. Они являются обобщением синглтона (статья 3), являясь по сути одним перечислимым элементом. Для читателей, знакомых с первой редакцией этой книги, перечислимые типы предоставляют лингвистическую поддержку безопасных перечислимых шаблонов [BlochOl, статья 21].

Перечислимые типы обеспечивают безопасность типов при компиляции. Если вы объявили, что параметр должен относиться к типу Apple, то у вас есть гарантия, что любая ненулевая ссылка на объект, переданная параметру, является одним из трех разрешенных значений Apple. Попытка передать значение неверного типа приведет к ошибке при компиляции, так же как и попытки присвоить выражение одного перечислимого типа переменной другого или использовать оператор == для сравнения значений различных перечислимых типов.

Перечислимые типы с одинаковыми наименованиями констант сосуществуют «мирно» потому, что у каждого типа имеется свое пространство имен. Вы можете добавлять или менять порядок констант в перечислимом типе без необходимости повторно компилировать клиентов, потому что поля, экспортирующие константы, предоставляют защитный слой между перечислимым типом и его клиентами: значения констант не компилируются в клиентов, как в случае с перечислимым шаблоном int. Наконец, вы можете перевести перечислимые типы в печатаемые строки вызовом метода toString.

В дополнение к тому, что перечислимые типы позволяют нам избавиться от недостатков перечислимых шаблонов int, они позволяют нам добавлять произвольные методы и поля, а также реализовывать произвольные интерфейсы. Они предлагают высококачественные реализации всех методов Object (глава 11), а их сериализованная форма сделана так, чтобы перенести большую часть изменений в перечислимых типах.

Так зачем нам добавлять методы или поля к перечислимым типам? Например, вы можете захотеть ассоциировать данные с их константами. Наши типы Apple или Orange, например, могут извлечь выгоду из метода, который вернет цвет фрукта или его изображение. Вы можете присвоить аргументы перечислимому типу с помощью любого подходящего метода. Перечислимый тип может начать жизнь, как простая коллекция перечислимых констант и развивается со временем в полноценную абстракцию.