Вопрос-ответ

When to choose checked and unchecked exceptions

Когда выбирать проверенные и непроверенные исключения

В Java (или любом другом языке с проверяемыми исключениями), при создании собственного класса исключений, как вы решаете, должен ли он быть отмечен или снят?

Мой инстинкт подсказывает, что проверяемое исключение будет вызываться в случаях, когда вызывающий может быть в состоянии восстановиться каким-либо продуктивным способом, где в качестве непроверенного исключения было бы больше для неустранимых случаев, но мне было бы интересно мнение других.

Переведено автоматически
Ответ 1

Проверенные исключения хороши, если вы понимаете, когда их следует использовать. Java core API не соблюдает эти правила для SQLException (а иногда и для IOException), вот почему они такие ужасные.

Проверяемые исключения следует использовать для предсказуемых, но непредотвратимых ошибок, которые разумно исправить.

Непроверенные исключения следует использовать для всего остального.

Я разберу это для вас, потому что большинство людей неправильно понимают, что это значит.


  1. Предсказуемо, но не предотвратимо: вызывающий объект сделал все, что в его силах, для проверки входных параметров, но какое-то условие вне его контроля привело к сбою операции. Например, вы пытаетесь прочитать файл, но кто-то удаляет его в промежутке между проверкой его существования и началом операции чтения. Объявляя проверяемое исключение, вы сообщаете вызывающей стороне, что она должна предвидеть этот сбой.

  2. Разумно восстанавливаться после: Нет смысла говорить вызывающим абонентам, что они должны предвидеть исключения, от которых они не могут восстановиться. Если пользователь пытается прочитать из несуществующего файла, вызывающий может запросить у него новое имя файла. С другой стороны, если метод выходит из строя из-за ошибки программирования (недопустимые аргументы метода или некорректная реализация метода), приложение ничего не может сделать, чтобы исправить проблему в середине выполнения. Лучшее, что он может сделать, это зарегистрировать проблему и ждать, пока разработчик исправит ее позже.

Если генерируемое вами исключение не удовлетворяет всем вышеперечисленным условиям, оно должно использовать непроверенное исключение.

Переоцените на каждом уровне: иногда метод, перехватывающий проверяемое исключение, не подходит для обработки ошибки. В таком случае подумайте, что разумно для ваших собственных вызывающих пользователей. Если исключение предсказуемо, непредотвратимо и разумно для восстановления, вам следует создать проверяемое исключение самостоятельно. Если нет, вам следует обернуть исключение в непроверяемое исключение. Если вы будете следовать этому правилу, вам придется преобразовывать проверенные исключения в непроверенные и наоборот, в зависимости от того, на каком уровне вы находитесь.

Как для проверенных, так и для непроверенных исключений, используйте правильный уровень абстракции. Например, репозиторий кода с двумя разными реализациями (база данных и файловая система) не должен раскрывать детали, зависящие от конкретной реализации, путем выдвижения SQLException или IOException. Вместо этого он должен обернуть исключение в абстракцию, которая охватывает все реализации (например, RepositoryException).

Ответ 2

От изучающего Java:


Когда возникает исключение, вы должны либо перехватить и обработать исключение, либо сообщить компилятору, что вы не можете его обработать, объявив, что ваш метод генерирует это исключение, тогда код, использующий ваш метод, должен будет обработать это исключение (даже он также может объявить, что он генерирует исключение, если он не может его обработать).


Компилятор проверит, что мы выполнили одно из двух действий (перехватили или объявили). Поэтому они называются проверяемыми исключениями. Но ошибки и исключения во время выполнения не проверяются компилятором (хотя вы можете перехватывать или объявлять, это не обязательно). Итак, эти два называются непроверенными исключениями.


Ошибки используются для представления тех условий, которые возникают вне приложения, таких как сбой системы. Исключения во время выполнения обычно возникают по ошибке в логике приложения. В таких ситуациях вы ничего не можете сделать. При возникновении исключения во время выполнения вам придется переписать программный код. Таким образом, они не проверяются компилятором. Эти исключения во время выполнения будут обнаружены в процессе разработки и тестирования. Затем мы должны провести рефакторинг нашего кода, чтобы удалить эти ошибки.


Ответ 3

Правило, которое я использую: никогда не используйте непроверенные исключения! (или когда вы не видите никакого способа обойти это)


Есть доводы в пользу обратного: никогда не используйте проверяемые исключения. Я неохотно принимаю чью-либо сторону в дебатах (у обеих сторон определенно есть веские аргументы!) но задним числом достаточное количество экспертов считают, что проверяемые исключения были неправильным решением.

Чтобы узнать о некоторых обсуждениях, загляните на WikiWikiWeb “Проверенные исключения имеют сомнительную ценность”. Другим примером раннего обширного спора является сообщение в блоге Рода Уолдхоффа.

Ответ 4

В любой достаточно большой системе со многими уровнями проверяемые исключения бесполезны, поскольку в любом случае вам нужна стратегия архитектурного уровня для обработки того, как будет обрабатываться исключение (используйте барьер ошибок)

С проверенными исключениями ваша система обработки ошибок управляется на микроуровне, и ее невозможно вынести в любой большой системе.

В большинстве случаев вы не знаете, "восстанавливаема" ли ошибка, потому что вы не знаете, на каком уровне находится вызывающий объект вашего API.

Допустим, я создаю API StringToInt, который преобразует строковое представление целого числа в Int. Должен ли я выдавать проверяемое исключение, если API вызывается со строкой "foo"? Это можно восстановить? Я не знаю, потому что на своем уровне вызывающий мой STRINGTOINTAPI, возможно, уже проверил входные данные, и если это исключение выдается, это либо ошибка, либо повреждение данных, и оно не подлежит восстановлению для этого уровня.

В этом случае вызывающий API не хочет перехватывать исключение. Он только хочет, чтобы исключение "всплывало". Если я выберу проверенное исключение, у этого вызывающего будет много бесполезного блока catch только для искусственного повторного создания исключения.

То, что можно восстановить, в большинстве случаев зависит от вызывающего API, а не от автора API. API не должен использовать проверенные исключения, поскольку только непроверенные исключения позволяют либо перехватывать, либо игнорировать исключение.

java exception