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

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

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

Барри Рузек написал отличный гид о выборе отмеченных или непроверенных исключений.

sigget 04.08.2009 16:58
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
229
1
57 451
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

От Ученик Java:

When an exception occurs, you have to either catch and handle the exception, or tell compiler that you can't handle it by declaring that your method throws that exception, then the code that uses your method will have to handle that exception (even it also may choose to declare that it throws the exception if it can't handle it).

Compiler will check that we have done one of the two things (catch, or declare). So these are called Checked exceptions. But Errors, and Runtime Exceptions are not checked for by compiler (even though you can choose to catch, or declare, it is not required). So, these two are called Unchecked exceptions.

Errors are used to represent those conditions which occur outside the application, such as crash of the system. Runtime exceptions are usually occur by fault in the application logic. You can't do anything in these situations. When runtime exception occur, you have to re-write your program code. So, these are not checked by compiler. These runtime exceptions will uncover in development, and testing period. Then we have to refactor our code to remove these errors.

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

artbristol 17.10.2012 12:02

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

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

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

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

Matthew Flaschen 21.02.2012 19:09

Полностью не согласен с вашим необоснованным ответом: «никогда не используйте неотмеченные исключения».

user1697575 18.03.2013 23:43

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

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

Я не согласен с вашим утверждением «Непроверенные исключения используются редко, если вообще используются», на самом деле все должно быть наоборот! Используйте неотмеченные исключения по умолчанию при разработке иерархии исключений приложения. Позвольте разработчикам решать, когда они хотят обработать исключение (например, они не обязаны помещать блоки catch или вставлять предложение throws, если они не знают, как с этим справиться).

user1697575 18.03.2013 23:41

The rule I use is: never use unchecked exceptions! (or when you don't see any way around it)

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

ИМХО, проверенные исключения могли быть основным активом, если бы для метода был простой способ объявить, что он не ожидает, что методы, вызываемые в конкретном блоке кода, будут генерировать определенные исключения (или какие-либо вообще), и что любой проверенный исключения, которые генерируются вопреки такому ожиданию, должны быть обернуты каким-либо другим типом исключения и созданы повторно. Я бы сказал, что в 90% случаев, когда код не готов справиться с проверенным исключением, такой перенос с повторным вызовом был бы лучшим способом справиться с этим, но из-за отсутствия языковой поддержки это делается редко.

supercat 08.03.2013 23:27

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

Konrad Rudolph 09.03.2013 00:46

У меня есть одно недовольство дизайном исключений, которое мог бы решить описанный мною механизм, заключается в том, что если foo задокументирован как выбрасывающий barException при чтении после конца файла, а foo вызывает метод, который выдает barException, даже если foo не ожидая этого, код, вызывающий foo, будет думать, что конец файла достигнут, и не будет знать, что произошло что-то неожиданное. Я бы рассмотрел эту ситуацию как ту, где проверенные исключения должен были бы наиболее полезными, но это также единственный случай, когда компилятор разрешает необработанные проверенные исключения.

supercat 09.03.2013 01:00

@supercat: для кода уже существует простой способ сделать то, что вы хотите в первом комментарии: обернуть код в блок try, перехватить исключение и обернуть исключение в RuntimeException и повторно выбросить.

Warren Dew 27.11.2017 03:42

@WarrenDew Я уверен, что Supercat знает об этом методе и считает, что он отсутствует из-за раздуваемого кода. Наличие декларативного стиля выражения этого (вместо того, чтобы каждый раз подробно его реализовывать) было бы огромным преимуществом. По сути, это возвращается к тому, чтобы иметь систему типов вместо того, чтобы писать свои собственные проверки типов вручную; то же самое, что и использование @NotNull, и проверка аргументов null с помощью if.

Konrad Rudolph 27.11.2017 13:29

@KonradRudolph: Конечно. Одна из отличительных черт хороших языков - то, что они заставляют Полегче делать правильные вещи, а не неправильные. Правильная упаковка неожиданных исключений в Java ни в коем случае не является невозможной, но это, безусловно, труднее, чем просто надеяться, что они никогда не возникнут таким образом, чтобы вызывающий абонент принял неожиданное условие за ожидаемое.

supercat 27.11.2017 18:33

@KonradRudolph supercat относится к «конкретному блоку кода»; учитывая, что блок должен быть определен, декларативный синтаксис существенно не уменьшит раздувание. Если вы думаете, что это будет декларативно для всей функции, это будет способствовать плохому программированию, поскольку люди просто будут придерживаться декларации вместо того, чтобы фактически смотреть на проверенные исключения, которые потенциально могут быть обнаружены, и убедиться, что нет другого лучшего способа справиться с ними.

Warren Dew 27.11.2017 20:34

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

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

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


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

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

  • контейнер объекта для создания / получения ДОЛЖЕН существовать (ответственность CALLER
    => исключенное исключение, И очистить комментарий javadoc для этой вызываемой функции)
  • остальные параметры не могут быть равны нулю
    (выбор кодировщика, чтобы поместить это в ЗВОНКУ: кодировщик не будет проверять нулевой параметр, но кодировщик ДОКУМЕНТУЕТ ЭТО)
  • результат НЕ МОЖЕТ БЫТЬ NULL
    (ответственность и выбор кода вызываемого, выбор которого будет интересен звонящему
    => проверенное исключение, потому что каждый вызывающий ДОЛЖЕН принять решение, если объект не может быть создан / найден, и это решение должно быть принудительно исполнено во время компиляции: они не могут использовать эту функцию, не имея дело с этой возможностью, то есть с этим проверил исключение).

Пример:


/**
 * 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;
}

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

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

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

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

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

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

Это очень близко к userstories.blogspot.com/2008/12/…

alexsmail 21.01.2012 08:43

@alexsmail Интернет меня не перестает удивлять, это вообще мой блог :)

Stephane 28.09.2013 21:29

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

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

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

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

Вы правы.

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

Например:

/**
 * @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 атрибутов, и ни один из них не может быть нулевым, вместо проверки в каждом из этих методов на допустимость значения NULL вы можете сделать все эти атрибуты доступными только для чтения и проверить их в конструкторе или заводской способ.

 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 не работает, повторите попытку позже и т. д.)

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

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

Хорошо сказано! +1. Меня всегда удивляет, что различие между вызывающим (не отмеченным) / вызываемым (отмеченным) не более очевидным ...

VonC 27.11.2008 07:49

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

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

Keith Pinson 17.11.2012 01:25

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

user1697575 18.03.2013 23:45

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

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

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

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

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

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

Ответ принят как подходящий

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

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

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

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

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

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

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

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

«вы пытаетесь прочитать файл, но кто-то удаляет его между моментом, когда вы проверяете, существует ли он, и моментом начала операции чтения». => Как это вообще «ожидается»? На мой взгляд, это больше похоже на: НЕОЖИДАННЫЙ и предотвратимый .. Кто мог ожидать, что файл будет удален только между двумя операторами?

Koray Tugay 27.11.2016 11:29

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

Gili 28.11.2016 06:12

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

ivanjermakov 26.10.2019 07:50

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

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

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

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

Могут быть сделаны более общие исключения. Не отмечено флажком, менее общие - отмечены.

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

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

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

где x равно нулю ... … Код, возможно, должен иметь следующее…

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 следуют двум правилам, указанным выше. Если вы попытаетесь записать в файл, диск может заполниться до завершения записи. Возможно, диск был заполнен другими процессами. Проверить эту ситуацию просто невозможно. Для тех, кто взаимодействует с оборудованием, где в любой момент его использование может дать сбой, проверенные исключения кажутся элегантным решением этой проблемы.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Если ошибка является ошибкой программиста, это должно быть исключение Unchecked Exception.. Например: SQLException / IOException / NullPointerException. Эти исключения ошибки программирования. Ими должен заниматься программист. Пока в JDBC API, SQLException - это проверенное исключение, в Spring JDBCTemplate это исключение без проверки. Программист не беспокоится о SqlException при использовании Spring.
  • Если ошибка не является ошибкой программиста, а причина исходит извне, это должно быть проверенное исключение. Например: если файл удален или права доступа к файлу изменены кем-то другим, Это должны быть восстановлены.

FileNotFoundException - хороший пример для понимания тонких различий. FileNotFoundException генерируется в случае, если файл не найден. Для этого исключения есть две причины. Если путь к файлу определен разработчиком или получен от конечного пользователя через графический интерфейс, это должно быть исключение Unchecked Exception. Если файл удален кем-то другим, это должно быть отмеченное исключение.

Отмеченное исключение можно обработать двумя способами. Они используют try-catch или распространяют исключение. В случае распространения исключения все методы в стеке вызовов будут тесно связаны из-за обработки исключения. Вот почему мы должны осторожно использовать Checked Exception.

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

Другие вопросы по теме