Вы пишете исключения для определенных проблем или общие исключения?

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

emailUtil.sendEmail(userId, "foo");

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

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

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

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

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

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

22.08.2008 02:47:44
11 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

throws SpecificException1, SpecificException2, SpecificException3 ...

генерал

throws GeneralException

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

8
19.05.2009 07:21:39

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

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

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

1
22.08.2008 03:00:04

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

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

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

public bool isEmailConfigured ()

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

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

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

10
9.02.2009 18:42:36
Вы также регистрируете свои исключения на стороне сервера?
pjp 7.08.2009 10:39:42
@php: Да, хорошо, если это код сервера. Для реальных клиентских приложений (не веб) у меня также обычно есть возможность регистрировать исключения на стороне клиента для отладки.
jm. 8.08.2009 17:21:54

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

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

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

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

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

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

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

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

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

1
3.11.2008 16:22:02
Исключения очень полезны и делают код более читабельным, если его правильно использовать. Производительность языковых функций, таких как исключения, меняется с каждым выпуском современных виртуальных машин, поэтому вы должны каждый раз сравнивать его с предложениями if (которые вы явно должны использовать для проверки результата метода). Проверки if для проверки результата методов загромождают ваш код и усложняют его поддержку. Не поймите меня неправильно - иногда объекты статуса - хорошее решение. Особенно, если вы обрабатываете несколько ошибок (как вы упоминали), они более полезны, чем исключения. Но решение должно быть продуманным.
Mnementh 14.08.2009 11:01:38

@ Chris.Lively

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

2
22.08.2008 04:46:00

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

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

0
22.08.2008 05:42:56

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

throw new exception("WhatCausedIt")

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

-1
22.08.2008 05:48:25
Вместо кода в Исключении, передаваемого в качестве параметра, вы можете создать подкласс исключений и использовать instanceof.
Mnementh 14.08.2009 10:55:12

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

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

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

0
22.08.2008 15:13:56

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

0
26.08.2008 01:57:30

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

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

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

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

1
26.08.2008 02:03:14

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

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

2
11.01.2009 19:28:08