Как лучше обработать ситуацию отсутствия файла: выбросить исключение или вывести диагностическое сообщение
Что проверяют
Понимаете ли вы, что выбор зависит не от вкуса, а от того, ожидаемо ли отсутствие файла и на каком уровне кода вы находитесь. Следом обычно спрашивают, кто в итоге показывает сообщение пользователю и что попадает в лог.
Как отвечать
Ответ строится на двух различиях.
Первое: ожидаемая ситуация или сбой. Если файл необязателен (пользовательский конфиг, кэш), это обычная ветка логики: верните Optional<Config> или значение по умолчанию и запишите строку уровня INFO. Если без файла работать нельзя, это исключение.
Второе: где вы находитесь. Сервисный код не должен ничего печатать, он не знает, кто его вызвал: консоль, веб-сервис или тест. Он бросает исключение с путём и причиной, а подачу выбирает граница приложения:
- CLI: понятное сообщение в
System.errи ненулевой код выхода; - веб-сервис: 404 или 500 через
@ControllerAdviceв Spring, полный стек в логе; - фоновая задача: лог уровня
ERRORи метрика для алерта.
Детали, которые стоит назвать:
- NIO и старый API:
Files.newBufferedReaderбросаетNoSuchFileException, аFileReaderиFileInputStreamбросаютFileNotFoundException. Оба наследуютIOException; - проверка
Files.existsперед открытием не спасает: файл могут удалить между проверкой и чтением. Надёжнее сразу открывать и ловить исключение; - оборачивание с причиной:
throw new ConfigLoadException("Нет конфига: " + path, e)сохраняет исходный стек; - try-with-resources закрывает поток при любом исходе.
Где спотыкаются
Ловят исключение, пишут System.out.println или e.printStackTrace(), и программа идёт дальше с пустыми данными. Ошибка всплывает позже и в другом месте, где причину уже не найти.
Путают уровни: выводят сообщение пользователю прямо из метода чтения файла. Такой метод потом не переиспользовать ни в сервисе, ни в тесте.
Теряют причину, бросая новое исключение без e в конструкторе, или ловят Exception целиком и заодно глотают ошибки доступа к файлу.