Можно ли в одном методе написать несколько catch блоков и в каком порядке их следует располагать?
Что проверяют
Знаете ли вы, как исключение сопоставляется с блоками catch и почему порядок проверяет компилятор ещё до запуска. Следом почти всегда просят рассказать про multi-catch и про то, чем опасна ловля Exception и Throwable.
Как отвечать
Да, у одного try может быть сколько угодно блоков catch. При исключении они проверяются сверху вниз, выполняется только первый подходящий, остальные пропускаются. Отсюда правила:
- сначала подклассы, потом суперклассы:
FileNotFoundExceptionвышеIOException,IOExceptionвышеException. Если общий тип стоит раньше, код не скомпилируется с ошибкойexception FileNotFoundException has already been caught, потому что нижний блок недостижим; - несвязанные типы: для
IOExceptionиSQLExceptionпорядок компилятору безразличен, выбор всё равно однозначен; - multi-catch (Java 7+):
catch (IOException | SQLException e)для одинаковой обработки. Типы в нём не могут быть родителем и потомком, иначе ошибка компиляции, а переменнаяeнеявноfinal; - недостижимый checked-блок:
catch (IOException e)приtry, который такое исключение бросить не может, тоже ошибка компиляции. НаException,Throwableи unchecked-исключения правило не распространяется.
Дополните картиной иерархии: Throwable делится на Error и Exception, внутри Exception есть ветка unchecked RuntimeException. Упомяните finally, который выполняется при любом исходе, и try-with-resources, где исключения из close() не теряются, а попадают в getSuppressed() основного.
Где спотыкаются
Говорят, что при неправильном порядке «сработает не тот блок». На деле программа просто не соберётся, и это стоит сказать прямо.
Ставят в конец catch (Throwable t) или catch (Exception e) с пустым телом. Так глотаются OutOfMemoryError, InterruptedException и обычные баги, после чего ошибку ищут по косвенным признакам.
Путают multi-catch с цепочкой: пишут catch (IOException | Exception e) и удивляются ошибке компиляции. Если нужен общий тип, достаточно одного Exception.