Каковы преимущества и недостатки проверяемых исключений (checked exceptions) в Java?

Ответ

Проверяемые исключения (checked exceptions) в Java — это исключения, которые компилятор заставляет явно обрабатывать или пробрасывать. Их использование вызывает споры в сообществе.

Преимущества:

  • Принудительная обработка ошибок: Компилятор гарантирует, что разработчик предусмотрел возможные сбои, что повышает надежность кода.
  • Явный контракт: Сигнатура метода явно объявляет, какие исключения он может выбросить, что служит документацией.

Недостатки:

  • Избыточный код (boilerplate): Часто приводит к цепочкам try-catch или объявлениям throws, которые загромождают код, особенно когда исключение не может быть осмысленно обработано на текущем уровне.
  • Нарушение инкапсуляции: Вынуждает раскрывать детали реализации (типы исключений) вышележащим слоям.
  • Сложность с лямбда-выражениями: Функциональные интерфейсы в Stream API и других местах не поддерживают проверяемые исключения, что усложняет их использование.

Пример проверяемого исключения:

public void readFile(String path) throws IOException { // Должно быть объявлено
    BufferedReader reader = new BufferedReader(new FileReader(path));
    // ...
}

Современный подход: Для многих сценариев предпочтительнее использовать непроверяемые исключения (наследники RuntimeException), которые не требуют обязательного объявления. Это делает код чище, а обработку ошибок — более централизованной (например, через глобальный обработчик @ControllerAdvice в Spring). Проверяемые исключения остаются уместными для действительно ожидаемых и восстановимых ошибок (например, FileNotFoundException при работе с пользовательским вводом).

Ответ 18+ 🔞

Да ты посмотри, что творят эти ваши проверяемые исключения в Java! Ну реально, ёпта, как будто компилятор взял тебя за шкирку и орёт: «А ну-ка, мудила, признавайся, что тут у тебя может пиздануться!»

Ну, типа, плюсы есть, не спорю:

  • Заставит обработать, хоть волком вой. Компилятор, сука, как надзиратель: не напишешь try-catch или throws — нахуй не скомпилирует. Вроде как надёжнее, да. Не проигноришь случайно.
  • Контракт явный, всё на виду. Глянул на метод — и сразу видишь, чем он тебя может, блядь, обрадовать. throws IOException, SQLException — ага, щас насрано будет.

Но минусы-то, блядь, какие!

  • Код превращается в помойку. Это ж сколько этого бойлерплейта, этой обёрточной хуйни! Сплошные try-catch-throws, а по факту часто просто пробрасываем наверх, потому что обрабатывать нихуя нечем. Просто чтобы компилятор отъебался.
  • Инкапсуляцию ебут. Внутренние кишки метода вылезают наружу в сигнатуру. Вышестоящему коду теперь похуй не класть, что там у тебя творится, он должен про твои FileNotFoundException знать.
  • С лямбдами вообще пиздец. Попробуй эту проверяемую хуйню в стрим запихнуть или в Function — сразу получишь, что твоя лямбда несовместима, потому что все эти @FunctionalInterface — трусливые пидарасы, throws не поддерживают. Приходится оборачивать в RuntimeException, а это уже, простите, извращение.

Вот, смотри, классика жанра:

public void readFile(String path) throws IOException { // Блядь, пришлось написать!
    BufferedReader reader = new BufferedReader(new FileReader(path));
    // ...
}

А сейчас, понимаешь, мода пошла другая. Умные дядьки говорят: «Да похуй!». Чаще используют непроверяемые исключения (RuntimeException). Код чище, не засран объявлениями, а все фатальные ошибки ловятся одним махом где-то на самом верху, в каком-нибудь глобальном обработчике. Проверяемые оставляют только для ситуаций, когда ошибку реально можно и нужно обработать прямо тут, на месте — ну, там, пользователь не тот файл выбрал, предупреди его, сука. А если всё полетело к чертям — то какая разница, проверяемое оно или нет, всё равно падать.