- •Содержание
- •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
В описание исключения добавляйте информацию о сбое
Если выполнение программы завершается аварийно из-за необработанного исключения, система автоматически распечатывает трассировку стека для этого исключения. Трассировка стека содержит строковое представление данного исключения, результат вызова его метода toString. Обычно это представление состоит из названия класса исключения и описания исключения (detail message). Часто это единственная информация, с которой приходится иметь дело программистам или специалистам по наладке, исследующим сбой программы. И если воспроизвести этот сбой нелегко, то получить какую-либо еще информацию будет трудно или даже вообще невозможно. Поэтому крайне важно, чтобы метод toString в классе исключения возвращал как можно больше информации о причинах отказа. Иными словами, строковое представление исключения должно зафиксировать отказ для последующего анализа.
Для фиксации сбоя строковое представление исключения должно содержать значения всех параметров и полей, "способствовавших появлению этого исключения". Например, описание исключения IndexOutOfBounds должно содержать нижнюю границу, верхнюю границу и действительный индекс, который .не уложился в эти границы. Такая информация говорит об отказе очень многое. Любое из трех значений или все они вместе могут быть неправильными. Представленный индекс может оказаться на единицу меньше нижней границы или быть равен верхней границе ("ошибка
171
границы" - fencepost error) либо может иметь несуразное значение, как слишком маленькое, так и слишком большое. Нижняя граница может быть больше верхней (серьезная ошибка нарушения внутреннего инварианта). Каждая из этих ситуаций указывает на свою проблему, и если программист знает, какого рода ошибку следует искать, это в огромной степени облегчает диагностику.
Хотя добавление в строковое представление исключения всех относящихся к делу "достоверных данных" является критическим, обычно нет надобности в том, чтобы оно было пространным. Трассировка стека, которая должна анализироваться вместе с исходными файлами приложения, как правило, содержит название файла и номер строки, где это исключение возникло, а также файлы и номера строк из стека, соответствующие всем остальным вызовам. Многословные пространные описания сбоя, как правило, излишни - необходимую информацию можно собрать, читая исходный текст программы.
Не, следует путать строковое представление исключения и сообщение об ошибке на пользовательском уровне, которое должно быть понятно конечным пользователям. В отличие от сообщения об ошибке, описание исключения нужно главным образом программистам и специалистам по наладке для анализа причин сбоя. Поэтому содержащаяся в строковом представлении информация гораздо важней его вразумительности.
Один из приемов, гарантирующих, что строковое представление исключения будет содержать информацию, достаточную для Описания сбоя, состоит в том, чтобы эта информация запрашивалась в конструкторах исключения, а в строке описания. Само же описание исключения можно затем генерировать автоматически для представления этой информации. Например, вместо конструктора String исключение IndexOutOfBounds могло бы иметь следующий конструктор:
/**
* Конструируем IndexOutOfBoundsException
* @раram lowerBound – самое меньшее из разрешенных значений индекса
* @param upperBound – самое большее из разрешенных значений индекса плюс один
* @раrаm index – действительное значение индекса
*/
Public IndexOutOfBoundsExoeption(int lowerBound, int index) {
// Генерируем описание исключения,
// фиксирующее обстоятельства отказа
super( "Lower bound: " + lowerBound +
“,Upper bound: " + uppe rBound +
“,Index: " + index);
}
172
К сожалению, хотя ее очень рекомендуют, эта идиома в библиотеках для платформы Java используется не слишком интенсивно. С ее помощью программист, инициирующий исключение, может с легкостью зафиксировать обстоятельства сбоя: Вместо того чтобы заставлять каждого пользующегося классом генерировать свое строковое представление, в этой идиоме собран фактически весь код, необходимый для того, чтобы 'качественное строковое представление генерировал сам класс исключения.
Как отмечалось в статье 40, возможно, имеет смысл, чтобы исключение предоставляло методы доступа к информации об обстоятельствах сбоя (в представленном выше примере это lowerBound, upperBound и Index). Наличие таких методов доступа для обрабатываемых исключений еще важнее, чем для необрабатываемых, поскольку информация об обстоятельствах сбоя может быть полезна для восстановления работоспособности программы. Программный доступ к деталям необрабатываемого исключения редко интересует программистов (хотя это и не исключено). Однако, согласно общему принципу (статья 9), такие методы доступа имеет смысл создавать .даже для необрабатываемых исключений.