Сначала определите договор метода
До выбора конструкции обработки ошибок запишите три вещи: что метод принимает, что возвращает при успехе и как сообщает о невозможности выполнить работу. Например, чтение пустого файла и отсутствие файла имеют разный смысл. Возвращать пустой список в обоих случаях удобно лишь внешне: следующая часть программы теряет возможность различить нормальный результат и сбой. Представьте коллегу, который видит только вызов метода. Достаточно ли ему описания, чтобы выбрать дальнейшее действие?
У ресурса должен быть понятный владелец
Файловые потоки требуют освобождения после использования. Для объектов, реализующих AutoCloseable, Java предоставляет try-with-resources: закрытие выполняется при выходе из соответствующего блока, в том числе при исключении. Несколько объявленных ресурсов закрываются в обратном порядке. Однако конструкция не отвечает за архитектурное решение, кому принадлежит ресурс. Если метод получил уже открытый поток от вызывающей стороны, обязанность закрытия следует явно согласовать. Иначе удобная локальная правка может неожиданно сломать дальнейшую работу другого компонента.
Сохраните сведения о причине
Когда ошибка произошла во время основной операции и при закрытии ресурса, try-with-resources сохраняет исключение основной операции, а ошибки закрытия становятся подавленными исключениями. Их можно получить через getSuppressed. Практический вопрос шире синтаксиса: какие сведения потребуются для диагностики? Полезны название операции и безопасный идентификатор задачи. Содержимое личного файла, пароль или токен не должны попадать в журнал ради удобства. Сообщение пользователю и техническая запись для разработчика могут иметь разную подробность.
Проверяйте решение в точках отказа
Составьте небольшую карту: до открытия, во время чтения, после обработки, при освобождении ресурса. Для каждой точки определите наблюдаемый исход. Не обязательно искусственно воспроизводить любую аппаратную поломку: часть сценариев удобно моделировать тестовым объектом с предсказуемым поведением. Сначала проверьте сам договор метода, затем детали реализации. Хороший тест объясняет, какую гарантию защищает. Проверка только текста сообщения часто слишком хрупкая; важнее убедиться, что ошибка не превращается в ложный успех и вызывающий код получает ожидаемый сигнал.
Попробуйте на практике
Спроектируйте проверку небольшого метода чтения без доступа к рабочим данным и внешним системам.
- Опишите вход, успешный результат и отдельный исход для отсутствующего файла. Используйте только специально созданные тестовые данные.
- Нарисуйте границы владения: кто открывает ресурс, кто использует и кто обязан закрыть его.
- Выберите три сценария: нормальное чтение, ошибка операции и ошибка закрытия тестового ресурса.
- Для каждого сценария запишите ожидаемое исключение, состояние результата и допустимые сведения в журнале.
- Сопоставьте ожидания с реализацией и добавьте проверки там, где поведение пока определяется случайно.
Как проверить результат. Результат готов, если у каждого ресурса есть владелец, нормальная пустота отличается от сбоя, а проверка аварийного пути не зависит от настоящей поломки или раскрытия личных данных.
Частые вопросы
Нужно ли перехватывать исключение в каждом методе?
Полезнее перехватывать там, где можно осмысленно обработать ситуацию, добавить необходимый контекст или перевести ошибку в договор другого уровня. Пустой обработчик скрывает проблему.
Достаточно ли автоматического закрытия?
Оно решает конкретную задачу жизненного цикла ресурса. Проверку входа, выбор реакции на ошибку и корректность итоговых данных всё равно нужно проектировать отдельно.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.