Как восстановить из непроверенного исключения?

голоса
4

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

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

Предположим , у меня есть веб - приложение, построенное с использованием Struts2 и спящий режим. Если исключение пузырьков до моих «действий», я вхожу, и отображать довольно извинения пользователя. Но одна из функций моего веб - приложения является создание новых учетных записей пользователей, для которых требуется уникальное имя пользователя. Если пользователь выбирает имя , которое уже существует, Hibernate генерирует org.hibernate.exception.ConstraintViolationException(неконтролируемое исключение) вниз в кишках моей системы. Я бы очень хотел , чтобы оправиться от этой конкретной проблемы, задавая пользователю выбрать другое имя пользователя, а не давая им тем же «мы вошли вашу проблему , но сейчас вы обливали» сообщение.

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

  1. Там много людей, создающих счета одновременно. Я не хочу, чтобы заблокировать всю таблицу пользователей между «SELECT», чтобы увидеть, если имя существует и «INSERT IGNORE», если он не делает. В случае реляционных баз данных, могут быть некоторые уловки, чтобы обойти это, но то, что я на самом деле интересует общий случай, когда предварительно проверка на исключение не будет работать из-за фундаментального состояния гонки. То же самое можно применить к поиску файла в файловой системе и т.д.
  2. Учитывая склонность моей CTO для привода руководством индуцированное чтения технологии колонок в «Inc.», мне нужен слой косвенности вокруг механизма персистенции, так что я могу выкинуть Hibernate и использовать Kodo, или любой другой, не меняя ничего, кроме самого низкого слой сохраняемости кода. В самом деле, есть несколько таких уровней абстракции в моей системе. Как я могу предотвратить их утечку, несмотря на непроверенное исключение?
  3. Одним из слабых мест продекламировал проверяемых исключений приходится «обрабатывать» их в каждом вызове в стеке, либо объявить , что вызывающий метод бросает их, или ловить их и обращаться с ними. Обращение с ними часто означает , что упаковка их в другом проверяемом исключении того или иного типа , соответствующего уровень абстракции. Так, например, в зарегистрированном исключении земли, файловая система , на основе реализация моего UserRegistry может поймать IOException, в то время как реализация базы данных будет ловить SQLException, но и бросить бы, UserNotFoundExceptionчто скрывает основную реализацию. Как воспользоваться непроверенным исключениями, избавляя себя от бремени этой упаковки на каждом уровне, без утечки детали реализации?
Задан 28/08/2008 в 22:57
источник пользователем
На других языках...                            


9 ответов

голоса
15

ИМО, оберточная исключения (проверка или иным образом) имеет ряд преимуществ, которые стоит стоимость:

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

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

3) Это позволяет стать реализацией независимой от нижнего кода уровня. Если вы оборачивать исключения и нужно поменять Hibernate для некоторых других ОРМ, вы только изменить Hibernate-код обработки. Все остальные слои коды все равно будут успешно используют обернутые исключения и интерпретируют их таким же образом, несмотря на то, что основные обстоятельства изменились. Обратите внимание, что это относится даже если Hibernate изменение каким-либо образом (например: они переключают исключения в новой версии); это не только для оптовой замены технологии.

4) Он призывает вас использовать различные классы исключений для представления различных ситуаций. Например, вы можете иметь DuplicateUsernameException, когда пользователь пытается повторно использовать имя пользователя и DatabaseFailureException, когда вы не можете проверить надуть имена пользователей из-за сломанное соединение DB. Это, в свою очередь, позволяет ответить на ваш вопрос ( «Как восстановить?») В гибких и мощных способов. Если вы получаете DuplicateUsernameException, вы можете решить, чтобы предложить другое имя для пользователя. Если вы получаете DatabaseFailureException, вы можете позволить этому пузырь до точки, где она отображает «вниз для обслуживания» страницы для пользователя и отправлять уведомление по электронной почте к вам. Если у вас есть собственные исключения, то есть изменяемые ответы - и это хорошо.

Ответил 28/08/2008 в 23:32
источник пользователем

голоса
3

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

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

Ответил 28/08/2008 в 23:02
источник пользователем

голоса
2

См Patterns для генерации, обработка и управление ошибками

Из рисунка Разделить домена и технические ошибки

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

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

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

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

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

Таким образом, оберните исключение спящего режима на границе в спящем режиме с непроверенным исключением домена, такими как «UniqueUsernameException», и пусть этот пузырем всех путями к обработчику этого. Убедитесь, что JavaDoc выброшенного исключения, даже если это не проверено исключение!

Ответил 16/09/2008 в 19:09
источник пользователем

голоса
1

Я согласен с Ником. Исключение вы описали это на самом деле не «непредвиденное исключение», так что вы должны разработать вам код в соответствии с возможными исключениями во внимание.

Кроме того, я рекомендовал бы взглянуть на документацию Microsoft Enterprise Library Exception Handling Блок имеет хороший план шаблонов обработки ошибок.

Ответил 28/08/2008 в 23:19
источник пользователем

голоса
1

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

Помогите?

Ответил 28/08/2008 в 23:05
источник пользователем

голоса
0

@erikson

Просто чтобы добавить еду ваши мысли:

Проверено против бесконтрольно также обсуждается здесь

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

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

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

Ответил 16/09/2008 в 16:30
источник пользователем

голоса
0

@Jan Проверено по сравнению с непроверенной центральным вопросом здесь. Я подвергаю сомнению ваше предположение (# 3) , что исключение должно быть проигнорировано в промежуточных кадров. Если я сделаю это, я в конечном итоге с зависимостью от конкретной реализации в моем коде высокого уровня. Если я заменяю Hibernate водосточных блоки по всей моей заявке должны быть изменены. Тем не менее, в то же время, если я ловлю исключение на более низком уровне, я не получаю много пользы от использования непроверенной исключения.

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

Ответил 02/09/2008 в 21:56
источник пользователем

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

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

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

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

    Как можно скорее мы ловим ConstraintViolationException и преобразовать его в MessageException с хорошим сообщением. Очень важно, чтобы преобразовать его в ближайшем время, когда мы можем быть уверены, что это действительно «уникальное имя пользователя ограничение», которое было нарушено, а не какое-то другое ограничение.

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

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

Код может выглядеть следующим образом

// insert the user
try {
   hibernateSession.save(user);
} catch (ConstraintViolationException e) {
   throw new MessageException("Username " + user.getName() + " already exists. Please choose a different name.");
}

В совершенно другом месте есть верхний обработчик исключений

try {
   ... render the page
} catch (MessageException e) {
   ... render a nice page with the message
} catch (Exception e) {
   ... render "we logged your problem but for now you're hosed" message
}
Ответил 02/09/2008 в 16:16
источник пользователем

голоса
0

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

try {
    throw new IllegalArgumentException();
} catch (Exception e) {
    System.out.println("boom");
}

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

Но я предполагаю, что в вашем сегодня это может быть Hibernate, а завтра рамки SleepLongerDuringWinter. В этом случае вам нужно притворяться, чтобы иметь свою собственную небольшую рамку ОРМА, которые обтекают рамки третьей стороны. Это позволит вам обернуть любые рамки конкретных исключения в более значимые и / или проверяемых исключения, которые вы знаете, как сделать лучше чувство.

Ответил 29/08/2008 в 00:36
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more