Что произойдёт в Java, если обработчик общего типа исключения объявлен перед обработчиком его подкласса?
Программа не скомпилируется: обработчик подкласса окажется недостижимым. Обработчики catch проверяются сверху вниз, поэтому общий обработчик перехватит исключение подкласса раньше.
Модель исключений Java использует иерархию типов: например, RuntimeException является наследником Exception. Последовательные блоки catch позволяют сначала обрабатывать частные случаи, а затем использовать общий резервный обработчик.
Чтобы такая последовательность не содержала заведомо мёртвый код, компилятор анализирует отношения между типами исключений и запрещает недостижимые обработчики.
Если общий обработчик расположен первым, до обработчика подкласса управление никогда не дойдёт. Это не просто неудачный порядок выполнения, а ошибка компиляции: Java заранее видит, что более специфичный catch не может быть выбран.
Неверный порядок особенно легко получить при добавлении нового обработчика в существующий код. В результате сборка перестанет проходить, хотя каждый блок catch по отдельности может быть корректным.
Обработчики проверяются в порядке их объявления. Для возникшего исключения выбирается первый catch, параметр которого совместим с фактическим типом исключения.
Этот код не компилируется: IllegalArgumentException уже входит в множество исключений, перехватываемых RuntimeException. Корректный порядок — сначала подкласс, затем родительский тип:
Проверяется именно совместимость типов, а не текст имени переменной или фактическое намерение разработчика. Если обработчик общего типа нужен только для логирования или преобразования исключения, он должен располагаться после всех более специфичных обработчиков.
Это правило относится к иерархии исключений независимо от того, являются они проверяемыми или непроверяемыми. При этом несколько альтернативных типов можно объединить в multi-catch, если между ними нет отношения наследования.
Сервис читает конфигурационный файл. Для отсутствующего файла требуется создать конфигурацию по умолчанию, для остальных ошибок чтения — вернуть ошибку запуска.
Вариант с обработчиком IOException перед FileNotFoundException не компилируется: FileNotFoundException является подклассом IOException. Перестановка обработчиков решает проблему, но требует учитывать, что специальная ветка должна действительно завершать обработку или передавать исключение дальше.
Альтернатива — один общий обработчик с проверкой типа внутри него. Такой подход хуже разделяет сценарии, усложняет код и может привести к случайному подавлению ошибок. Поэтому предпочтительно расположить FileNotFoundException первым, IOException — вторым, а обработчик более общего уровня использовать только в конце.
catch после частного делает частный обработчик достижимым?Да, если частный тип действительно является подклассом общего и исключение может быть выброшено из соответствующего try. В таком порядке сначала проверяется частный случай, а затем общий. Если типы не связаны наследованием, оба обработчика также могут быть достижимыми.
Выбор catch выполняется по фактическому типу объекта во время выполнения, а не по статическому типу переменной. Поэтому объект IllegalArgumentException, сохранённый в переменной типа Exception, сначала попадёт в обработчик IllegalArgumentException, если он расположен до общего обработчика Exception.
Нет. Такая конструкция запрещена, потому что один из типов полностью покрывает другой, а значит один вариант становится недостижимым. Multi-catch подходит для независимых типов исключений, когда для них нужна одинаковая обработка и ни один тип не является подтипом другого.