- •Содержание
- •1. Введение
- •2. Создание и уничтожение объектов
- •3. Методы, общие для всех объектов
- •4. Классы и интерфейсы
- •5. Замена конструкций на языке c
- •6. Методы
- •7. Общие вопросы программирования
- •8. Исключения
- •9. Потоки
- •10. Сериализация
- •11. Литература
- •Глава 1
- •Глава 2 Создание и уничтожение объектов
- •Рассмотрите возможность замены конструкторов статическими методами генерации.
- •Свойство синглтона обеспечивайте закрытым конструктором
- •Отсутствие экземпляров обеспечивает закрытый конструктор
- •Не создавайте дублирующих объектов
- •Уничтожайте устаревшие ссыпки (на объекты)
- •Остерегайтесь методов flnalize
- •Глава 3 Методы, общие для всех объектов
- •Переопределяя метод equals, соблюдайте общие соглашения
- •Переопределяя метод equals, всегда переопределяйте hashCode
- •Всегда переопределяйте метод toStrlng
- •Подумайте над реализацией интерфейса ComparabIe
- •Глава 4 Классы и интерфейсы
- •Сводите к минимуму доступность классов и членов
- •Предпочитайте постоянство
- •Предпочитайте компоновку наследованию
- •Предпочитайте интерфейсы абстрактным классам.
- •Используйте интерфейсы только для определения типов
- •Предпочитайте статические классы-члены нестатическим
- •Глава 5
- •3Амена констрvкций на языке с
- •3Аменяйте структуру классом
- •3Амеияйте объедииеиие иерархией классов
- •/* Помещает данные в одно из полей объединения ... */
- •3Аменяйте конструкцию enum классом
- •Указатель на функцию заменяйте кпассом и интерфейсом
- •Глава 6 Методы
- •Проверяйте достоверность параметров
- •При необходимости создавайте резервные копии
- •Тщательно проектируйте сигнатуру метода
- •Перегружая методы, соблюдайте осторожность
- •Возвращайте массив нулевой длины, а не null
- •Для всех открытых элементов арi пишите dос - комментарии
- •Глава 7 Общие вопросы программирования
- •Сводите к минимуму область видимости локальных переменных
- •Изучите библиотеки и пользуйтесь ими
- •Не используйте строку там, где более уместен иной тип
- •При конкатенации строк опасайтесь потери производительности
- •Для ссыпки на объект используйте его интерфейс
- •Соблюдайте осторожность при использовании машинно-зависимых методов
- •Соблюдайте осторожность при оптимизации
- •Глава 8 Исключения
- •Используйте исключения лишь в исключительных ситуациях
- •Применяйте обрабатываемые исключения для восстановления, для программных ошибок используйте исключения времени выполнения
- •Избегайте ненужных обрабатываемых исключений
- •Предпочитайте стандартные исключения
- •Инициируйте исключения, соответствующие абстракции
- •Для каждого метода документируйте все инициируемые исключения
- •В описание исключения добавляйте информацию о сбое
- •Добивайтесь атомарности методов по отношению к сбоям
- •Не игнорируйте исключений
- •Глава 9 Потоки
- •Синхронизируйте доступ потоков к совместно используемым изменяемым данным
- •Избегайте избыточной синхронизации
- •Никогда не вызывайте метод wait вне цикла
- •Не попадайте в зависимость от планировщика потоков
- •При работе с потоками документируйте уровень безопасности
- •Избегайте группировки потоков
- •Глава 10 Сериализация
- •Соблюдайте осторожность при реализации интерфейса SerializabIe
- •Рассмотрите возможность использования специализированной сериализованной формы
- •Метод readObject должен создаваться с защитой
- •При необходимости создавайте метод readResolue
Избегайте ненужных обрабатываемых исключений
Обрабатываемые исключения -' замечательная особенность языка программирования Java. В отличие от возвращаемых кодов, они заставляют программиста отслеживать условия возникновения исключений, что значительно повышает надежность приложения. Это означает, что злоупотребление обрабатываемыми исключениями может сделать API менее удобным для использования. Если метод инициирует одно или несколько обрабатываемых исключений, то в программном коде, из которого этот метод был вызван, должна присутствовать обработка этих исключений в виде одного или нескольких блоков catch, либо должно быть декларировано, что этот код сам инициирует исключения и передает их дальше. В любом случае перед программистом стоит нелегкая задача.
Такое решение оправданно, если даже при надлежащем применении интерфейса API невозможно предотвратить возникновение условий для исключительной ситуации, однако программист, пользующийся данным API, столкнувшись с этим исключением, мог бы предпринять какие-либо полезные действия. Если не выполняются оба этих условия, лучше пользоваться необрабатываемым исключением. Роль лакмусовой бумажки в данном случае играет вопрос: как программист будет обрабатывать исключение? Является ли это решение лучшим:
} catch(TheCheckedException е) {
throw new Error("Assertion error");
// Условие не выполнено. Этого не должно быть никогда!
}
А что скажете об этом:
} catch(TheCheckedException e) {
e.printStackTrace(); //Ладно, закончили работу.
System. exit( 1); }
Если программист, применяющий API, не может сделать ничего лучшего, то больше подходит необрабатываемое исключение. Примером исключения, не выдерживающего подобной проверки, является CloneNotSupportedException. Оно инициируется
163
методом Object. сlоnе, который должен использоваться лишь для объектов, реализующих интерфейс Cloneable (статья 10). Блок catch практически всегда соответствует невыполнению утверждения. Так что обрабатываемое исключение не дает программисту преимуществ, но требует от последнего дополнительных усилий и усложняет программу.
Дополнительные действия со стороны программиста, связанные с обработкой обрабатываемого исключения, значительно увеличиваются, если это единственное исключение, инициируемое данным методом. Если есть другие исключения, метод будет стоять в блоке try, так что для этого исключения понадобится всего лишь еще один блок catch. Если же метод инициирует только одно обрабатываемое исключение, оно будет требовать, чтобы вызов соответствующего метода был помещен в блок try. В таких условиях имеет смысл подумать: не существует ли какого-либо способа избежать обрабатываемого исключения.
Один из приемов, позволяющих превратить обрабатываемое исключение в необрабатываемое, состоит в раз биении метода, инициирующего исключение, на два метода, первый из которых будет возвращать булево значение, указывающее, будет ли инициироваться исключение. Таким образом, в результате преобразования АРI последовательность вызова
// Вызов с обрабатываемым исключением
try {
obj.action(args);
catch(TheCheckedException е) {
// Обработать исключительную ситуацию
}
принимает следующий вид:
// Вызов с использованием метода проверки состояния
// и необрабатываемого исключения
if (obj.actionPermitted(args)) {
obj.action(args); }
else{ }
// Обработать исключительную ситуацию
Такое преобразование можно использовать не всегда, Если же оно допустимо, это может сделать работу с АРI более удобной. Хотя второй вариант последовательности вызова выглядит не лучше первого, полученный АРI имеет большую гибкость, В ситуации, когда программист знает, что вызов будет успешным, или согласен на завершение потока в случае неудачного вызова, преобразованный АРI позволяет использовать следующую упрощенную последовательность вызова:
obj,aotion(args):
164
Если вы предполагаете, что применение упрощенной последовательности вызова будет нормой, то описанное преобразование АР! приемлемо. API, полученный в результате этого преобразования, в сущности, тот же самый, что и АР! с методом "проверки состояния" (статья 39). Следовательно, к нему относятся те же самые предупреждения: если к объекту одновременно и без внешней синхронизации могут иметь доступ сразу несколько потоков или этот объект может менять свое состояние по команде извне, указанное преобразование использовать не рекомендуется. Это связано с тем, что в промежутке между вызовом actionPermitted и вызовом action состояние объекта может успеть поменяться. Если метод actionPermitted при необходимости и мог бы дублировать работу метода action, то от преобразования, вероятно, стоит отказаться по соображениям производительности.