В чем разница между checked и unchecked исключениями в Java и как они работают?
Что проверяют
Знаете ли вы иерархию и понимаете ли, когда какое исключение уместно. Заодно смотрят, не глотаете ли вы исключения.
Как отвечать
Корень иерархии это Throwable, у него две ветви: Error (сбои среды, обрабатывать не принято) и Exception.
Проверяемые (checked) это Exception и его потомки, кроме RuntimeException. Компилятор требует либо обработать их, либо объявить в throws. Смысл в том, что это ожидаемые ситуации внешнего мира: файла нет, сеть недоступна, база отказала.
Непроверяемые (unchecked) это RuntimeException и его потомки, а также Error. Компилятор ничего не требует. Смысл: ошибка программиста, которую надо чинить в коде, а не обрабатывать. NullPointerException, IllegalArgumentException, IndexOutOfBoundsException.
Как выбирать при проектировании: если вызывающий может осмысленно отреагировать (повторить, показать сообщение, взять другой источник), это проверяемое; если ситуация означает ошибку в коде, непроверяемое.
Практика последних лет сместилась к непроверяемым: они не засоряют сигнатуры и не заставляют пробрасывать throws через десять слоёв. Spring, например, переводит все исключения доступа к данным в непроверяемые. Лямбды и стримы тоже плохо дружат с проверяемыми исключениями.
Полезно назвать try-with-resources для гарантированного закрытия и подавленные исключения, которые там появляются.
Где спотыкаются
Глотают исключение пустым catch и теряют причину.
Ловят Exception вместо конкретного типа.
Оборачивают в RuntimeException, теряя исходное исключение как причину.
Используют исключения для обычного потока управления, что дорого и запутывает.