Best practices
Тема дорожной карты · Java
Лучшие практики обработки исключений в Java — это соглашения, отличающие устойчивый, сопровождаемый код от хрупких систем, подверженных ошибкам; следование им не менее важно, чем понимание иерархии исключений. Никогда не перехватывайте Exception или Throwable широко, если только вы не создаёте барьер ошибок верхнего уровня (например, фильтр сервлета или @ControllerAdvice) — широкий перехват поглощает неожиданные RuntimeException-ы и делает ошибки невидимыми; предпочитайте конкретные типы вроде IOException или TimeoutException. Всегда сохраняйте исходную причину при повторном бросании: throw new ServiceException("Failed to load order", e) передаёт корневую причину e, сохраняя полный стек вызовов доступным через getCause(), что незаменимо при диагностике производственных проблем по журналам. Используйте try-with-resources для всего, реализующего AutoCloseable — Connection, PreparedStatement, ResultSet, InputStream, Path-based readers, — чтобы ресурсы закрывались даже при возникновении исключения, предотвращая исчерпание пула соединений и утечки файловых дескрипторов, которые преследуют JDBC-приложения. Не используйте исключения для нормального управления потоком: бросание исключения для сигнализации о пустом optional или выхода из цикла — это антипаттерн, поскольку создание исключения JVM фиксирует стек вызовов за O(глубина) стоимость; используйте Optional, проверки на null или возвращаемые значения boolean для ожидаемых условий. Журналируйте исключения на той границе, где вы их обрабатываете, и нигде больше — журналирование и повторное бросание одного и того же исключения создаёт дублированные, вводящие в заблуждение стеки в инструментах производственной наблюдаемости.
Как это работает
Best practices делится на checked (нужно объявить или обработать — IOException, SQLException) и unchecked (RuntimeException — NullPointerException, IllegalArgumentException). try { } catch (...) { } finally { } или try-with-resources (try (var x = ...) { }) для AutoCloseable-типов — рекомендуется для файлов/сокетов/соединений. Multi-catch (catch (IOException | SQLException e)) сокращает дублирование. Всегда сохраняйте cause (throw new MyException(msg, cause)).
Когда применять
Checked exceptions — для восстановимых условий в API библиотек (вызывающий решает); unchecked (RuntimeException) — для программных ошибок. Оборачивайте checked exceptions на границах модулей, чтобы stack trace upstream оставался чистым. try-with-resources — для всего AutoCloseable. Логируйте с throwable (log.error("...", e)) — slf4j отформатирует со stack trace.
Типичные ошибки
Ловушки Best practices: catch (Exception e) { } тихо съедает каждую ошибку (тихий убийца); checked exceptions для того, что должно быть runtime-ошибкой (многословные declarations повсюду); rewrap exception теряет cause (throw new MyException(msg) без e — stack trace пропал); finally-блок, бросающий exception (оригинальное теряется).