Вы пишете исключения для определенных проблем или общие исключения? - PullRequest
10 голосов
/ 22 августа 2008

У меня есть некоторый код, который дает идентификатор пользователя утилите, которая затем отправляет электронное письмо этому пользователю.

emailUtil.sendEmail(userId, "foo");

public void sendEmail(String userId, String message) throws MailException {
    /* ... logic that could throw a MailException */
}

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

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

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

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

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

Ответы [ 11 ]

10 голосов
/ 22 августа 2008

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

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

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

public bool isEmailConfigured ()

... сначала позвоните, а не ищите конкретное исключение.

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

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

8 голосов
/ 26 сентября 2008

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

Примером Java-API является IOException, который имеет подклассы, такие как FileNotFoundException или EOFException (и многие другие).

Таким образом, вы получаете преимущества обоих, у вас нет таких предложений броска, как:

throws SpecificException1, SpecificException2, SpecificException3 ...

общее

throws GeneralException

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

2 голосов
/ 11 января 2009

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

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

2 голосов
/ 22 августа 2008

@Chris.Lively

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

1 голос
/ 26 августа 2008

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

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

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

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

1 голос
/ 22 августа 2008

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

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

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

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

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

ОБНОВЛЕНИЕ: объединение ответов

@ Джонатан: Моя точка зрения заключалась в том, что я могу оценить действие, в данном случае отправить электронное письмо, и отправить обратно несколько причин сбоя. Например, «неверный адрес электронной почты», «пустой заголовок сообщения» и т. Д.

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

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

1 голос
/ 22 августа 2008

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

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

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

0 голосов
/ 26 августа 2008

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

0 голосов
/ 22 августа 2008

Несмотря на то, что вы можете дифференцировать выполнение кода, просматривая исключение, не имеет значения, выполняется ли это «режимом иерархии catchceptionType» или «if (...) else ... режим кода исключения»

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

Когда я использую библиотеку и их методы просто запускают «Исключение», я всегда задаюсь вопросом: что может вызвать это исключение? Как должна реагировать моя программа ?, Если есть javadoc, возможно, причина будет объяснена, но должна раз нет javadoc или исключение не объясняется. Слишком много накладных ведьм можно избежать с помощью WellChossenExceptionTypeName

0 голосов
/ 22 августа 2008

Я бы просто пошел на

throw new exception("WhatCausedIt")

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

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