Как устроены исключения в Java, их иерархия и обработка ошибок
Что проверяют
Отличаете ли вы ошибку программиста от ожидаемого сбоя и умеете ли ставить границы обработки. Вопрос звучит базовым, но по ответу видно, писали ли вы код, который живёт в проде. Следом спрашивают, чем throw отличается от throws и что вернёт метод, если return есть и в try, и в finally.
Как отвечать
Начните с иерархии:
Throwable: корень, от него растут две ветки;Error:OutOfMemoryError,StackOverflowError. Ловить не принято, восстановиться на этом уровне обычно нельзя;- checked: наследники
Exception, кромеRuntimeException. Компилятор требует либоcatch, либоthrowsв сигнатуре:IOException,SQLException; - unchecked:
RuntimeExceptionи потомки,NullPointerException,IllegalArgumentException. Это дефекты кода, их чинят, а не обрабатывают.
Дальше механика: try / catch / finally, мультикэтч catch (IOException | SQLException e) с Java 7, try-with-resources для всего, что реализует AutoCloseable. В нём ресурс закрывается до входа в catch, а исключение из close() не затирает основное, а уходит в getSuppressed().
Практика, которую ждут:
- ловить конкретный тип, а не
Exception; - при переброске сохранять причину:
throw new OrderException("...", e), иначе исходный стектрейс потерян; - не ставить
returnвнутриfinally, он проглотит исключение; - на границе приложения (
@ControllerAdvice) переводить исключение в ответ с кодом, а не отдавать наружу стектрейс.
Плюсом: с Java 14 подробные сообщения NPE (JEP 358) прямо называют, какая ссылка оказалась null.
Где спотыкаются
Заявляют, что checked-исключения это зло, и оборачивают всё в RuntimeException. Позиция рабочая, но её надо защитить: где ловите, как отличаете сбой сети от бага.
Пишут log.error(e.getMessage()) без самого исключения. В логе остаётся строчка вроде null, а стектрейс теряется: передавайте объект вторым аргументом.
Считают, что finally отработает при любом раскладе. При System.exit() или падении JVM блок не выполнится.