В Java (или любом другом языке с проверенными исключениями), когда вы создаете свой собственный класс исключений, как вы решаете, следует ли его проверять или не проверять?
Мой инстинкт должен сказать, что проверенное исключение будет вызываться в тех случаях, когда вызывающий может быть в состоянии восстановиться каким-либо продуктивным способом, где в качестве неконтролируемого исключения будет больше для неисправимых случаев, но меня будут интересовать мысли других.
java
exception
checked-exceptions
Мэтт Шеппард
источник
источник
Ответы:
Проверенные исключения велики, если вы понимаете, когда их следует использовать. API ядра Java не соблюдает эти правила для SQLException (а иногда и для IOException), поэтому они так ужасны.
Проверенные исключения должны использоваться для предсказуемых , но не поддающихся проверке ошибок, которые целесообразно исправлять .
Непроверенные исключения должны быть использованы для всего остального.
Я сломаю это для вас, потому что большинство людей неправильно понимают, что это значит.
Если исключение, которое вы выбрасываете, не удовлетворяет всем вышеперечисленным условиям, следует использовать исключение Unchecked.
Переоценка на каждом уровне : иногда метод, перехватывающий проверенное исключение, не подходит для обработки ошибки. В этом случае подумайте, что является разумным для ваших абонентов. Если исключение предсказуемо, непредсказуемо и разумно для их восстановления, то вы должны бросить проверенное исключение самостоятельно. Если нет, вы должны заключить исключение в непроверенное исключение. Если вы будете следовать этому правилу, вы обнаружите, что конвертируете проверенные исключения в непроверенные исключения и наоборот, в зависимости от того, в каком слое вы находитесь.
Для проверенных и непроверенных исключений используйте правильный уровень абстракции . Например, хранилище кода с двумя различными реализациями (база данных и файловая система) должно избегать раскрытия деталей, относящихся к реализации, с помощью броска
SQLException
илиIOException
. Вместо этого следует обернуть исключение в абстракцию, которая охватывает все реализации (напримерRepositoryException
).источник
От ученика Java :
источник
Есть очень веские аргументы в пользу обратного: никогда не используйте проверенные исключения. Я не хочу принимать участие в дебатах, но, похоже, существует широкий консенсус в отношении того, что введение проверенных исключений было неправильным решением задним числом. Пожалуйста, не стреляйте в мессенджера и обращайтесь к этим аргументам .
источник
foo
задокументировано, как выбрасываниеbarException
при чтении после конца файла, иfoo
вызывает метод, который выбрасывает,barException
даже еслиfoo
не ожидает этого, код, который вызывает,foo
будет думать, что конец файла достигнут, и не будет иметь ни малейшего понятия, что произошло что-то неожиданное. Я бы посчитал, что в такой ситуации проверенные исключения должны быть наиболее полезными, но это также единственный случай, когда компилятор допускает необработанные проверенные исключения.В любой достаточно большой системе со многими слоями проверенные исключения бесполезны, так как, в любом случае, вам нужна стратегия архитектурного уровня для обработки того, как будет обрабатываться исключение (используйте барьер ошибок)
С проверенными исключениями ваша система обработки ошибок является микроуправляемой и невыносимой в любой большой системе.
В большинстве случаев вы не знаете, является ли ошибка «исправимой», потому что вы не знаете, на каком уровне находится вызывающая сторона вашего API.
Допустим, я создаю API-интерфейс StringToInt, который преобразует строковое представление целого числа в Int. Должен ли я генерировать проверенное исключение, если API вызывается со строкой "foo"? Это восстановимо? Я не знаю, потому что на своем уровне вызывающая сторона моего API StringToInt, возможно, уже проверила ввод, и если выбрасывается это исключение, это либо ошибка, либо повреждение данных, и его невозможно восстановить для этого уровня.
В этом случае вызывающая сторона API не хочет перехватывать исключение. Он только хочет, чтобы исключение «всплыло». Если я выбрал проверенное исключение, у этого вызывающего будет много бесполезных блокировок перехвата только для искусственного отбрасывания исключения.
То, что подлежит восстановлению, в большинстве случаев зависит от вызывающего API, а не от создателя API. API не должен использовать отмеченные исключения, поскольку только непроверенные исключения позволяют выбрать либо перехват, либо игнорирование исключения.
источник
Ты прав.
Непроверенные исключения используются для быстрого сбоя системы, и это хорошо. Вы должны четко указать, что ожидает ваш метод, чтобы работать должным образом. Таким образом, вы можете проверить ввод только один раз.
Например:
Просто чтобы привести пример. Дело в том, что если система быстро выходит из строя, то вы будете знать, где и почему она не сработала. Вы получите трассировку стека, как:
И ты узнаешь, что случилось. OtherClass в методе "DelegateTheWork" (в строке 4569) вызвал ваш класс со значением "exit", даже если это не так и т. Д.
В противном случае вам придется разбрасывать валидации по всему коду, и это может привести к ошибкам. Кроме того, иногда трудно отследить, что пошло не так, и вы можете ожидать часов отрыва отладки
То же самое происходит с исключениями NullPointerException. Если у вас есть класс на 700 строк с 15 методами, который использует 30 атрибутов, и ни один из них не может иметь значение null, вместо проверки в каждом из этих методов на обнуляемость вы можете сделать все эти атрибуты доступными только для чтения и проверить их в конструкторе или заводской метод.
Проверенные исключения полезны, когда программист (вы или ваши коллеги) все сделали правильно, проверил ввод, выполнил тесты, и весь код безупречен, но код подключается к стороннему веб-сервису, который может быть недоступен (или файл вы использовали был удален другим внешним процессом и т. д.). Веб-служба может даже быть проверена перед попыткой подключения, но во время передачи данных что-то пошло не так.
В этом случае вы или ваши коллеги ничего не можете сделать, чтобы помочь ему. Но все же вы должны что-то сделать и не дать приложению просто умереть и исчезнуть в глазах пользователя. Для этого вы используете проверенное исключение и обрабатываете исключение, что вы можете делать, когда это происходит? Большую часть времени вы просто пытаетесь записать ошибку, возможно, сохранить свою работу (работу приложения) и представить сообщение пользователю. , (Сайт blabla не работает, повторите попытку позже и т. Д.)
Если проверенное исключение чрезмерно используется (добавление «throw Exception» во все сигнатуры методов), тогда ваш код станет очень хрупким, потому что все будут игнорировать это исключение (потому что оно слишком общее), и качество кода будет серьезно скомпрометированы.
Если вы злоупотребите непроверенным исключением, произойдет нечто подобное. Пользователи этого кода не знают, если что-то пойдет не так, появится много попыток {...} catch (Throwable t).
источник
Вот мое «последнее правило».
Я использую:
По сравнению с предыдущим ответом, это четкое обоснование (с которым можно согласиться или не согласиться) для использования одного или другого (или обоих) исключений.
Для обоих этих исключений я создам свое собственное исключение без проверки и с проверкой для моего приложения (хорошая практика, как упомянуто здесь ), за исключением очень распространенного исключения без проверки (например, NullPointerException)
Так, например, целью этой конкретной функции ниже является создание (или получение, если оно уже существует) объекта, что
означает:
непроверенное исключение CALLER => и очистить комментарий javadoc для этой вызываемой функции)
(выбор кодера для помещения его в CALLER: кодер не будет проверять нулевой параметр, но кодер ДОКУМЕНТИТ ЭТО)
(ответственность и выбор кода вызываемого абонента, выбор, который будет представлять большой интерес для
проверяемого исключения вызывающего абонента =>, поскольку каждый вызывающий абонент ДОЛЖЕН принять решение, если объект не может быть создан / найден, и что решение должно быть исполнено во время компиляции: они не могут использовать эту функцию без необходимости иметь дело с этой возможностью, то есть с этим проверенным исключением).
Пример:
источник
Дело не только в способности оправиться от исключения. На мой взгляд, больше всего важно, заинтересован ли вызывающий абонент поймать исключение или нет.
Если вы пишете библиотеку для использования в другом месте или слой более низкого уровня в своем приложении, спросите себя, заинтересован ли вызывающий абонент поймать (узнать о) ваше исключение. Если это не так, используйте исключение без проверки, чтобы вы не обременяли его без необходимости.
Это философия, используемая многими системами. В частности, приходят на ум Spring и Hibernate - они преобразуют известное проверенное исключение в непроверенное исключение именно потому, что проверенные исключения чрезмерно используются в Java. Одним из примеров, который я могу вспомнить, является JSONException от json.org, который является проверенным исключением и в основном раздражает - его следует отключить, но разработчик просто не продумал его.
Кстати, в большинстве случаев интерес вызывающего абонента к исключению напрямую связан с возможностью восстановления после исключения, но это не всегда так.
источник
Вот очень простое решение вашей проверенной / непроверенной дилеммы.
Правило 1. Думайте о непроверенном исключении как о тестируемом условии перед выполнением кода. например…
где х нуль ... ... код должен иметь следующее ...
Правило 2. Думайте о проверяемом исключении как о непроверяемом условии, которое может возникнуть во время выполнения кода.
… В приведенном выше примере URL (google.com) может быть недоступен из-за неработоспособности DNS-сервера. Даже в тот момент, когда DNS-сервер работал и преобразовал имя «google.com» в IP-адрес, если в любой момент после подключения к google.com сеть может выйти из строя. Вы просто не можете все время проверять сеть перед чтением и записью в потоки.
Есть моменты, когда код просто должен исполниться, прежде чем мы узнаем, есть ли проблема. Вынуждая разработчиков писать свой код таким образом, чтобы заставить их справляться с этими ситуациями с помощью Checked Exception, я вынужден склонить голову создателю Java, который придумал эту концепцию.
В общем, почти все API в Java следуют 2 приведенным выше правилам. Если вы попытаетесь записать файл, диск может заполниться до завершения записи. Возможно, что другие процессы вызвали переполнение диска. Просто нет способа проверить эту ситуацию. Для тех, кто взаимодействует с оборудованием, где в любое время использование оборудования может дать сбой, Проверенные исключения кажутся элегантным решением этой проблемы.
Здесь есть серая зона. В случае, если требуется много тестов (ошеломляющее утверждение if с большим количеством && и ||), генерируемое исключение будет CheckedException просто потому, что слишком много боли, чтобы получить право - вы просто не можете сказать эту проблему это ошибка программирования. Если тестов намного меньше 10 (например, «if (x == null)»), то ошибка программиста должна быть UncheckedException.
Вещи становятся интересными, когда имеешь дело с переводчиками. Согласно приведенным выше правилам, следует ли считать синтаксическую ошибку проверенным или непроверенным исключением? Я бы сказал, что если синтаксис языка можно протестировать до его запуска, это должно быть исключение UncheckedException. Если язык не может быть протестирован - аналогично тому, как ассемблерный код выполняется на персональном компьютере, то синтаксическая ошибка должна быть проверенным исключением.
2 приведенных выше правила, вероятно, уберут 90% вашего беспокойства, из которого можно выбирать. Чтобы суммировать правила, следуйте этому шаблону… 1) если выполняемый код может быть проверен перед тем, как он будет выполнен, чтобы он выполнялся правильно, и если возникает Исключение - то есть ошибка программиста, то Исключением должно быть UncheckedException (подкласс RuntimeException). ). 2) если код, который должен быть выполнен, не может быть протестирован, прежде чем он будет выполнен для правильной работы, исключение должно быть проверенным исключением (подкласс исключения).
источник
Вы можете назвать это проверенным или непроверенным исключением; однако программист может перехватить оба типа исключений, поэтому лучший ответ таков: запишите все свои исключения как непроверенные и задокументируйте их. Таким образом, разработчик, который использует ваш API, может выбрать, хочет ли он или она перехватить это исключение и что-то сделать. Проверенные исключения являются пустой тратой времени каждого, и это делает ваш код ужасным кошмаром. Правильное модульное тестирование затем вызовет любые исключения, которые вам, возможно, придется поймать и что-то сделать.
источник
Проверено исключение: если клиент может восстановиться после исключения и хочет продолжить, используйте проверенное исключение.
Непроверенное исключение: если клиент не может ничего сделать после исключения, тогда вызовите непроверенное исключение.
Пример: Если вы должны выполнять арифметическую операцию в методе A () и на основе выходных данных из A (), вам нужно выполнить другую операцию. Если выходные данные из метода A () являются нулевыми, чего вы не ожидаете во время выполнения, то ожидается, что вы получите исключение нулевого указателя, которое является исключением времени выполнения.
Обратитесь сюда
источник
Я согласен с предпочтением для непроверенных исключений, как правило, особенно при разработке API. Вызывающий всегда может выбрать перехват зарегистрированного, непроверенного исключения. Ты просто не заставляешь звонящего.
Я считаю проверенные исключения полезными на нижнем уровне, как детали реализации. Часто кажется, что механизм управления потоком данных лучше, чем управлять заданным ошибочным «кодом возврата». Иногда это может помочь увидеть влияние идеи на низкоуровневое изменение кода тоже ... объявить проверенное исключение в нисходящем направлении и посмотреть, кого нужно будет скорректировать. Этот последний пункт не применяется, если есть много общего: catch (Exception e) или throws Exception, которое обычно не слишком хорошо продумано в любом случае.
источник
Вот я хочу поделиться своим мнением, которое у меня есть после многолетнего опыта разработки:
Проверено исключение. Это часть бизнес-прецедента или потока вызовов, это часть логики приложения, которую мы ожидаем или не ожидаем. Например, соединение отклонено, условие не выполнено и т. Д. Мы должны обработать его и показать пользователю соответствующее сообщение с инструкциями, что произошло и что делать дальше (повторите попытку позже и т. Д.). Я обычно называю это исключением пост-обработки или "пользовательским" исключением.
Непроверенное исключение. Это является частью исключения из программирования, некоторой ошибкой в программировании программного кода (ошибка, дефект) и отражает то, как программисты должны использовать API согласно документации. Если внешний документ lib / framework сообщает, что ожидает получить данные в некотором диапазоне и не в нулевом, потому что будет выброшено исключение NPE или IllegalArgumentException, программист должен ожидать его и правильно использовать API в соответствии с документацией. В противном случае будет выдано исключение. Я обычно называю это исключением предварительной обработки или исключением «проверки».
По целевой аудитории. Теперь давайте поговорим о целевой аудитории или группе людей, для которых были разработаны исключения (по моему мнению):
По этапу жизненного цикла разработки приложения.
Причина, по которой фреймворки обычно используют неконтролируемые исключения (например, Spring), заключается в том, что фреймворк не может определить бизнес-логику вашего приложения, поэтому разработчики должны поймать и спроектировать собственную логику.
источник
Мы должны различать эти два типа исключений в зависимости от того, является ли это ошибкой программиста или нет.
FileNotFoundException является хорошим примером для понимания тонких различий. FileNotFoundException генерируется, если файл не найден. Есть две причины для этого исключения. Если путь к файлу определен разработчиком или получен от конечного пользователя через графический интерфейс, это должно быть непроверенное исключение. Если файл удален кем-то другим, это должно быть проверенное исключение.
Проверенное исключение может быть обработано двумя способами. Они используют try-catch или распространяют исключение. В случае распространения исключения все методы в стеке вызовов будут тесно связаны из-за обработки исключения. Вот почему мы должны использовать Checked Exception осторожно.
В случае, если вы разрабатываете многоуровневую корпоративную систему, вам нужно выбрать в основном непроверенное исключение, но не забудьте использовать проверенное исключение, если вы ничего не можете сделать.
источник
Проверенные исключения полезны для восстанавливаемых случаев, когда вы хотите предоставить информацию вызывающей стороне (например, недостаточно прав, файл не найден и т. Д.).
Непроверенные исключения используются редко, если вообще используются, для информирования пользователя или программиста о серьезных ошибках или неожиданных условиях во время выполнения. Не бросайте их, если вы пишете код или библиотеки, которые будут использоваться другими, поскольку они могут не ожидать, что ваше программное обеспечение сгенерирует непроверенные исключения, поскольку компилятор не заставляет их перехватывать или объявлять.
источник
Везде, где исключение ожидается менее вероятным, и мы можем действовать даже после его обнаружения, и мы не можем ничего сделать, чтобы избежать этого исключения, тогда мы можем использовать проверенное исключение.
Всякий раз, когда мы хотим сделать что-то значимое, когда происходит определенное исключение, и когда это исключение ожидается, но не обязательно, тогда мы можем использовать проверенное исключение.
Всякий раз, когда исключение перемещается в разных слоях, нам не нужно перехватывать его в каждом слое, в этом случае мы можем использовать исключение времени выполнения или обернуть исключение как исключение без проверки.
Исключение во время выполнения используется, когда исключение, скорее всего, произошло, нет пути идти дальше, и ничто не может быть восстановлено. Таким образом, в этом случае мы можем принять меры предосторожности в отношении этого исключения. Пример: NUllPointerException, ArrayOutofBoundsException. Это с большей вероятностью произойдет. В этом сценарии мы можем принять меры предосторожности при кодировании, чтобы избежать такого исключения. В противном случае мы должны будем написать try catch и везде блоки.
Более общие исключения могут быть сделаны Не проверены, менее общие проверяются.
источник
Я думаю, что мы можем думать об исключениях из нескольких вопросов:
почему происходит исключение? Что мы можем сделать, когда это произойдет
по ошибке ошибка. такой как метод нулевого объекта называется.
Такое исключение должно быть исправлено во время теста. В противном случае, это нарушает производство, и вы получаете очень большую ошибку, которую нужно немедленно исправить. Этот вид исключений не нужно проверять.
с помощью внешнего ввода вы не можете контролировать или доверять выходу внешнего сервиса.
Здесь вам может понадобиться проверить, является ли имя пустым, если вы хотите продолжить, когда оно пустое, в противном случае вы можете оставить его в покое, и оно остановится и выдаст вызывающему исключение времени выполнения. Этот вид исключений не нужно проверять.
по исключению времени выполнения из внешнего, вы не можете контролировать или доверять внешней службе.
Здесь вам может понадобиться перехватить все исключения из ExternalService, если вы хотите продолжить, когда это произойдет, в противном случае вы можете оставить его в покое, и он остановится здесь и даст вызывающей стороне исключение времени выполнения.
проверенным исключением из внешнего, вы не можете контролировать или доверять внешнему сервису.
Здесь вам может понадобиться перехватить все исключения из ExternalService, если вы хотите продолжить, когда это произойдет, в противном случае вы можете оставить его в покое, и он остановится здесь и даст вызывающей стороне исключение времени выполнения.
В этом случае нам нужно знать, что за исключение произошло в ExternalService? Это зависит:
если вы можете обрабатывать некоторые виды исключений, вам нужно их перехватить и обработать. Для других, пузырь их.
если вам нужен лог или ответ пользователю конкретного исполнения, вы можете их поймать. Для других, пузырь их.
источник
Я думаю, что при объявлении Application Exception это должно быть Unchecked Exception, то есть подкласс RuntimeException. Причина в том, что он не будет загромождать код приложения try-catch и выдает объявление метода. Если ваше приложение использует Java Api, который выдает проверенные исключения, которые в любом случае необходимо обрабатывать. В других случаях приложение может выдать непроверенное исключение. Если вызывающему приложению все еще нужно обработать непроверенное исключение, это можно сделать.
источник
Правило, которое я использую: никогда не используйте непроверенные исключения! (или когда ты не видишь никакого пути вокруг этого)
С точки зрения разработчика, использующего вашу библиотеку, или конечного пользователя, использующего вашу библиотеку / приложение, это действительно отстой, когда вы сталкиваетесь с приложением, которое вылетает из-за необработанного исключения. И рассчитывать на ловушку все тоже не годится.
Таким образом, конечный пользователь все еще может получить сообщение об ошибке, а приложение полностью исчезнет.
источник