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

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

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

Ответы

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

Из Java Learner:

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

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

Ты прав.

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

Например:

/**
 * @params operation - The operation to execute.
 * @throws IllegalArgumentException if the operation is "exit"
 */
 public final void execute( String operation ) {
     if( "exit".equals(operation)){
          throw new IllegalArgumentException("I told you not to...");
     }
     this.operation = operation; 
     .....  
 }
 private void secretCode(){
      // we perform the operation.
      // at this point the opreation was validated already.
      // so we don't worry that operation is "exit"
      .....  
 }

Просто чтобы привести пример. Дело в том, что если система быстро выйдет из строя, вы узнаете, где и почему это произошло. Вы получите стек:

 IllegalArgumentException: I told you not to use "exit" 
 at some.package.AClass.execute(Aclass.java:5)
 at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
 ar ......

И вы узнаете, что произошло. Метод OtherClass в методе "delegateTheWork" (в строке 4569) называется вашим классом со значением "exit", даже если он не должен и т.д.

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

То же самое происходит с NullPointerExceptions. Если у вас есть класс 700 строк с примерно 15 методами, который использует 30 атрибутов, и ни один из них не может быть нулевым, вместо проверки в каждом из этих методов для nullability вы можете сделать все эти атрибуты доступными только для чтения и проверить их в конструкторе или factory.

 public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
      if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }

  }


  // the rest of the methods don't validate data1 anymore.
  public void method1(){ // don't worry, nothing is null 
      ....
  }
  public void method2(){ // don't worry, nothing is null 
      ....
  }
  public void method3(){ // don't worry, nothing is null 
      ....
  }

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

В этом сценарии нет ничего, что вы или ваши коллеги можете сделать, чтобы помочь ему. Но все же вы должны что-то сделать и не позволять приложению просто умереть и исчезнуть в глазах пользователя. Вы используете проверенное исключение для этого и обрабатываете исключение, что вы можете делать, когда это происходит?, Большую часть времени просто пытайтесь зарегистрировать ошибку, возможно, сохраните свою работу (работа приложения) и представите сообщение пользователю, (Сайт blabla не работает, повторите попытку позже и т.д.)

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

Если вы злоупотребляете неконтролируемым исключением, произойдет что-то подобное. Пользователи этого кода не знают, может ли что-то подействовать неправильно, появится много попыток {...} catch (Throwable t).

Ответ 6

Вот мое "окончательное эмпирическое правило".
Я использую:

  • исключено исключение в коде моего метода для отказа из-за вызывающего (который включает явный и полная документация)
  • проверено исключение для отказа из-за callee, что я необходимо указать всем, кто хочет использовать мой код.

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


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

Так, например, целью этой конкретной функции ниже является создание (или получение, если уже существует) объекта,
что означает:

  • контейнер объекта, чтобы сделать/получить ДОЛЖЕН существовать (ответственность CALLER
    = > unchecked exception, AND clear javadoc comment для этой вызываемой функции)
  • другие параметры не могут быть нулевыми (выбор кодера для установки на CALLER: кодер не будет проверять нулевой параметр, но кодер ДОКУМЕНТ IT)
  • результат не может быть NULL
    (ответственность и выбор кода вызываемого абонента, выбор, который будет представлять большой интерес для вызывающего абонента = > checked exception, потому что каждый вызывающий должен принять решение, если объект не может быть создан/найден, и это решение должно быть исполнено во время компиляции: они не могут использовать эту функцию, не имея дело с этой возможностью, исключение).

Пример:


/**
 * Build a folder. <br />
 * Folder located under a Parent Folder (either RootFolder or an existing Folder)
 * @param aFolderName name of folder
 * @param aPVob project vob containing folder (MUST NOT BE NULL)
 * @param aParent parent folder containing folder 
 *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
 * @param aComment comment for folder (MUST NOT BE NULL)
 * @return a new folder or an existing one
 * @throws CCException if any problems occurs during folder creation
 * @throws AssertionFailedException if aParent is not in the same PVob
 * @throws NullPointerException if aPVob or aParent or aComment is null
 */
static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
    final IPVob aPVob, final Comment aComment) throws CCException {
    Folder aFolderRes = null;
    if (aPVob.equals(aParent.getPVob() == false) { 
       // UNCHECKED EXCEPTION because the caller failed to live up
       // to the documented entry criteria for this function
       Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }

    final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
        " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);

    final Status st = getCleartool().executeCmd(ctcmd);

    if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
        aFolderRes = Folder.getFolder(aFolderName, aPVob);
    }
    else {
        // CHECKED EXCEPTION because the callee failed to respect his contract
        throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
    }
    return aFolderRes;
}

Ответ 7

Это не просто вопрос о возможности восстановления из исключения. Самое важное, на мой взгляд, заключается в том, заинтересован ли вызывающий абонент в исключении или нет.

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

Это философия, используемая многими структурами. Spring и в спящем режиме, в частности, приходят на ум - они конвертируют известное исключенное исключение в исключенное исключение именно потому, что проверенные исключения чрезмерно используются в Java. Одним из примеров, который я могу придумать, является JSONException из json.org, который является проверенным исключением и в основном раздражает - он должен быть снят, но разработчик просто не думал об этом.

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

Ответ 8

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

Ответ 9

Вот очень простое решение для вашей проверенной/непроверенной дилеммы.

Правило 1: подумайте о неконтролированном исключении в качестве проверяемого условия перед выполнением кода. например...

x.doSomething(); // the code throws a NullPointerException

где x равно null... ... код должен иметь следующее...

if (x==null)
{
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
}
x.doSomething();

Правило 2: подумайте о проверенном исключении как о не проверяемом состоянии, которое может возникнуть во время выполнения кода.

Socket s = new Socket("google.com", 80);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

... в приведенном выше примере URL (google.com) может быть недоступен из-за отказа DNS-сервера. Даже в тот момент, когда DNS-сервер работал и разрешил "имя google.com на IP-адрес, если соединение было сделано на google.com, в любое время послесловия, сеть может опуститься. Вы просто не можете тестировать сеть все время перед чтением и записью в потоки.

Бывают случаи, когда код просто должен выполняться, прежде чем мы сможем узнать, есть ли проблема. Заставляя разработчиков писать свой код таким образом, чтобы заставить их обрабатывать эти ситуации через Checked Exception, я должен опрокинуть свою шляпу создателю Java, который изобрел эту концепцию.

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

Здесь есть серая область. В случае, когда требуется много тестов (размытие ума, если выражение с множеством && и ||), созданное исключение будет исключением CheckedException просто потому, что его слишком большая боль, чтобы получить право - вы просто не можете сказать это проблема - ошибка программирования. Если существует намного меньше 10 тестов (например, "if (x == null)), тогда ошибка программиста должна быть исключением UncheckedException.

Вещи становятся интересными при работе с переводчиками. Согласно вышеприведенным правилам, должна ли Синтаксическая ошибка считаться проверенным или непроверенным Исключением? Я бы сказал, что если синтаксис языка может быть протестирован до его выполнения, это должно быть исключение UncheckedException. Если язык не может быть протестирован - аналогично тому, как код сборки работает на персональном компьютере, тогда ошибка синтаксиса должна быть проверенным исключением.

2 правила выше, вероятно, удалят 90% вашей озабоченности, на которую можно выбрать. Чтобы обобщить правила, следуйте этой схеме... 1) если проверяемый код может быть протестирован перед его выполнением, чтобы он работал правильно, и если возникло исключение - a.k.a. ошибка программиста, исключение должно быть исключением UncheckedException (подкласс RuntimeException). 2) если код, который должен быть выполнен, не может быть протестирован до его выполнения, чтобы он работал правильно, Исключение должно быть проверенным исключением (подкласс Exception).

Ответ 10

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

Непроверенное исключение: Если клиент не может ничего сделать после исключения, то снимите непроверенное исключение.

Пример. Если вы ожидаете выполнить арифметическую операцию в методе A() и на основе вывода из A(), вы должны выполнить другую операцию. Если вывод является нулевым из метода A(), который вы не ожидаете в течение времени выполнения, тогда вы ожидаете выбросить исключение Null Exception, которое является исключением времени выполнения.

Обратитесь здесь

Ответ 11

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

Я нахожу проверенные исключения полезными на нижнем уровне, как подробности реализации. Это часто кажется лучшим потоком механизма управления, чем управление заданной ошибкой "код возврата". Иногда это может помочь увидеть влияние идеи на изменение кода низкого уровня тоже... объявить проверенное исключение ниже по течению и посмотреть, кто будет нуждаться в настройке. Эта последняя точка не применяется, если существует много общего: catch (исключение e) или выбрасывает исключение, которое обычно не слишком хорошо продумано.

Ответ 12

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

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

Ответ 13

Всякий раз, когда исключение менее вероятно, ожидается, и мы можем продолжить даже после того, как поймаем это, и мы не можем ничего сделать, чтобы избежать этого исключения, тогда мы можем использовать проверенное исключение.

Всякий раз, когда мы хотим сделать что-то значимое, когда происходят определенные исключения и когда это исключение ожидается, но не определено, мы можем использовать проверенное исключение.

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

Исключение исключений времени выполнения используется, когда, скорее всего, произойдет исключение, нет способа двигаться дальше, и ничто не может быть восстановлено. Поэтому в этом случае мы можем принять меры предосторожности в отношении этого исключения. EX: NUllPointerException, ArrayOutofBoundsException. Скорее всего, это произойдет. В этом случае мы можем принять меры предосторожности во время кодирования, чтобы избежать такого исключения. В противном случае нам придется писать блоки try catch где угодно.

Можно сделать более общие исключения. Непроверенные, менее общие проверяются.

Ответ 14

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

Почему происходит exeption? Что мы можем сделать, когда это произойдет?

по ошибке, вызывается ошибка., такая как метод нулевого объекта.

String name = null;
... // some logics
System.out.print(name.length()); // name is still null here

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

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

String name = ExternalService.getName(); // return null
System.out.print(name.length());    // name is null here

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

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

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

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

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

В этом случае нам нужно знать, какое исключение произошло в ExternalService? Это зависит:

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

  • если вам нужен журнал или ответ пользователю на конкретное исполнение, вы можете их поймать. Для других, пузырь их.

Ответ 15

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

  • Проверено исключение. Это часть бизнес-использования или потока вызовов, это часть логики приложения, которую мы ожидаем или не ожидаем. Например, соединение отклонено, условие не выполняется и т.д. Нам нужно обработать его и показать соответствующее сообщение пользователю с инструкциями, что произошло и что делать дальше (повторите попытку позже и т.д.). Обычно я называю это пост-обработкой исключение или исключение пользователя.

  • Исключено исключение. Это часть исключения для программирования, некоторая ошибка в программировании программного кода (ошибка, дефект) и отражает способ, которым программисты должны использовать API в соответствии с документацией. Если внешний документ lib/framework говорит, что он ожидает получить данные в некотором диапазоне и не равен нулю, потому что NPE или IllegalArgumentException будут выбрасываться, программист должен ожидать этого и правильно использовать API в соответствии с документацией. В противном случае будет выбрано исключение. Обычно я называю это исключение предварительной обработки или исключение "проверки".

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

  • Проверено исключение. Целевая аудитория - пользователи/клиенты.
  • Исключено исключение. Целевая аудитория - это разработчики. Другими словами, исключенное исключение предназначено только для разработчиков.

По фазе жизненного цикла разработки приложений.

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

Причина, по которой фреймворки обычно используют исключенные исключения (например, Spring), заключается в том, что инфраструктура не может определить бизнес-логику вашего приложения, это зависит от того, как разработчики поймают и разработают собственную логику.

Ответ 16

Я думаю, что при объявлении исключения приложения это должно быть Unchecked Exception, т.е. подкласс RuntimeException. Причина в том, что он не будет загромождать код приложения с помощью метода try-catch и throw for. Если ваше приложение использует Java Api, который выдает проверенные исключения, которые в любом случае должны обрабатываться. В других случаях приложение может вызывать неконтролируемое исключение. Если вызывающему приложению по-прежнему требуется обработать исключение, которое может быть выполнено, это можно сделать.

Ответ 17

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

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

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