Эта статья посвящена некоторым недопониманиям в выборе и использовании исключений Java. Я надеюсь, что читатели смогут овладеть некоторыми из пунктов и принципов обработки исключений и обратить внимание на краткое изложение и индукцию. Только путем обращения с исключениями мы можем улучшить основные качества разработчиков, повысить надежность системы, улучшить пользовательский опыт и повысить ценность продукта.
Неправильное понимание 1. Ненормальный выбор
Рисунок 1. Классификация аномалий
На рисунке 1 описывается структура исключения. Фактически, мы все знаем, что аномалии делятся на обнаружение аномалий и не определяющих аномалий, но на практике применение этих двух нарушений смущено. Поскольку не определенные исключения просты в использовании, многие разработчики считают, что обнаружение исключений бесполезно. Фактически, аномальные сценарии применения можно обобщить следующим образом:
1. Код вызова не может быть выполнен и должен быть немедленно прекращен. Для этой ситуации слишком много возможностей, таких как сервер, не подключены, параметры неверны и т. Д. Не определенные исключения применимы в настоящее время, и нет необходимости вызывать явное захват и обработку кода, а код является кратким и ясным.
2. Призывающий код нуждается в дальнейшей обработке и восстановлении. Если SQLEXCEPTION определяется как не определенные исключения, разработчики, естественно, полагают, что SQLEXCEPTION не требует вызова явного захвата и обработки кода, что приведет к серьезным ситуациям, таким как не закрытие соединения, не откатывание обратно транзакции и грязные данные в DB. Это именно потому, что SQLexception определяется как обнаружение исключений, что разработчики будут привлечены к четкому захвату и очистке ресурсов после того, как код генерирует исключение. Конечно, после очистки ресурсов вы можете продолжать бросать неопределенные исключения, чтобы предотвратить выполнение программы. Согласно наблюдению и пониманию, обнаружение исключений может быть в основном применено к классам инструментов. Java Learning Group 669823128
Недоразумение 2: отображать исключения непосредственно на странице или клиенте.
Обычно печатать исключения непосредственно на стороне клиента. Принимая JSP в качестве примера, как только код запускается, контейнер печатает информацию о стеке исключений непосредственно на странице по умолчанию. На самом деле, с точки зрения клиента, любое исключение не имеет практического значения, и большинство клиентов вообще не могут понять информацию об исключении. Разработка программного обеспечения также должна стараться не представить исключение непосредственно пользователям.
Список 1
<strong> package </strong> com.ibm.dw.sample.exception;/*** custom runtimeexception* добавить атрибут кода ошибки*/<strong> public </strong> <strong> class </strong> <strong> runtimeexcept <strong> public </strong> <strong> static </strong> <strong> final </strong> integer generic = 1000000; // код ошибки <strong> private </strong> Integer ErrorCode; <strong> public </strong> <strong> runtimeexception </strong> (целочисленный код ошибки, бросаемая причина) {<strong> this </strong> (ErrorCode, <strong> null </strong>, причина); } <strong> public </strong> <strong> runtimeexception </strong> (строковое сообщение, бросаемое причина) {// Использовать общий код ошибки <strong> this </strong> (generic, сообщение, причина); } <strong> public </strong> <strong> runtimeexception </strong> (целочисленный код ошибки, строковое сообщение, причина бросания) {<strong> super </strong> (сообщение, причина); <strong> this </strong> .errorCode = errorCode; } <strong> public </strong> integer <strong> geterRorCode </strong> () {<strong> return </strong> errorCode; }}Как показывает пример кода, введите коды ошибок в исключения. Как только происходит исключение, мы просто представляем код ошибки исключения из пользователя или преобразовываем код ошибки в более понятную подсказку. Фактически, код ошибки здесь также содержит другую функцию, и разработчики также могут точно знать, какой тип исключения произошел на основе кода ошибки.
Заблуждение 3: Загрязнение иерархии кодекса
Мы часто делим код на различные иерархии, такие как сервис, бизнес -логика, DAO и т. Д. Слои DAO будут содержать методы броска исключений, как показано в списке 2:
Листинг 2
<strong> public </strong> Customer <strong> retieVecustomerbyid </strong> (Long Id) <strong> Thress </strong> sqlexception {// Запросить базу данных на основе идентификатора}На первый взгляд, нет проблем с приведенным выше кодом, но если вы тщательно думаете с точки зрения связей с дизайном, SQLEXCEPTION здесь загрязняет верхний вызов. Призывенный слой должен явно использовать Try-Catch для захвата или дальнейшего добавления его на более высокий уровень. Согласно принципу изоляции дизайна, мы можем соответствующим образом изменить его на:
Листинг 3
<strong>public</strong> Customer <strong>retrieveCustomerById</strong>(Long id) { <strong>try</strong>{ //Query the database based on ID}<strong>catch</strong>(SQLException e){ //Use non-detected exception encapsulation to detect exceptions, reduce hierarchical coupling<strong>throw</strong> <strong>new</strong> Runtimeexception (sqlerrorcode, e); } <strong> наконец </strong> {// Закройте соединение и очистить ресурсы}}Заблуждение 4: игнорируйте исключения
Следующая обработка исключений просто выводит исключение из консоли, и это не имеет смысла. Более того, здесь появляется исключение, и программа не прерывается, и код вызова продолжается выполнять, что приводит к большему количеству исключений.
Список 4
<strong> public </strong> <strong> void </strong> <strong> retiveObjectById </strong> (long id) {<strong> try </strong> {//.. Какой -то код, который выбрасывает Sqlexception} <strong> Catch </strong> (sqlexception ex) {/****** * В производственной среде стек ошибок должен быть выведен в журнал. * И программа продолжает выполняться после процесса улова, что приведет к дальнейшим проблемам*/ ex.printstacktrace (); }}Может быть восстановлен:
Список 5
<strong>public</strong> <strong>void</strong> <strong>retrieveObjectById</strong>(Long id){ <strong>try</strong>{ //..some code that throws SQLException } <strong>catch</strong>(SQLException ex){ <strong>throw</strong> <strong>new</strong> RuntimeException("Exception <strong>in</strong> retrieveObjectById", бывший); } <strong> наконец </strong> {// Очистить результаты, оператор, соединение и т. Д.}}Это недоразумение является относительно простым, и при нормальных обстоятельствах вы не будете совершать эту ошибку низкого уровня.
Заблуждение 5: включить исключения в блоки операторов цикла
Как показано в следующем коде, исключение содержится в блоке операторов для цикла для цикла.
Список 6
<strong> для </strong> (<strong> int </strong> i = 0; i <100; i ++) {<strong> try </strong> {} <strong> catch </strong> (xxxexception e) {//…. }}Мы все знаем, что обработка исключений занимает системные ресурсы. На первый взгляд все думали, что они не совершат такую ошибку. С другой стороны, в цикле выполняется цикл в классе A, а метод класса B называется в цикле, но метод, вызванный в классе B, содержит блоки операторов, такие как Try-Catch. Иерархия класса исчезла, и код точно такой же, как и выше.
Заблуждение 6: Используйте исключение, чтобы запечатлеть все потенциальные исключения
Несколько различных типов исключений брошены во время выполнения метода. Для простоты кода исключение базового класса используется для улавливания всех потенциальных исключений, как показано в следующем примере:
Список 7
<strong> public </strong> <strong> void </strong> <strong> retiveObjectById </strong> (long ID) {<strong> try </strong> {//… код, который вызывает ioException //… Кодовый вызов, который бросает SQLException} <strong> Catch </strong> (Exception e) {// Здесь все потенциальные исключения, пойманные в исключитель базового класса. Если несколько уровней поймают это, допустимая информация об исходном исключении будет потеряна <strong> </strong> <strong> new </strong> runtimeexception («Исключение <strong> в </strong> retiveObjectbyId", e); }}Может быть восстановлен
Список 8
<strong>public</strong> <strong>void</strong> <strong>retrieveObjectById</strong>(Long id){ <strong>try</strong>{ //..some code that throws RuntimeException, IOException, SQLException }<strong>catch</strong>(IOException e){ // Just catch IOException <strong>throw</strong> <strong>new</strong> Runtimeexception (/*Укажите код ошибки, соответствующий ioexception здесь*/code, "Exception <strong> в </strong> retiveObjectByid", e); } <strong> catch </strong> (sqlexception e) {// просто поймать sqlexception <strong> throw </strong> <strong> new </strong> runtimeexception (/*Укажите код ошибки, соответствующий SQLException здесь*/Code, «Exception <strong> в </strong> retiveObjectByid», E); }}Заблуждение 7: многоуровневая инкапсуляция бросает не обнаруженные исключения
Если мы всегда настаиваем на том, что разные типы исключений должны использовать различные операторы захвата, то большинство примеров могут обойти этот раздел. Тем не менее, если только один кусок кодовых вызовов вызовет более одного исключения, часто нет необходимости писать оператор CATCE для каждого другого типа исключения. Для разработки любого исключения достаточно, чтобы объяснить конкретную проблему программы.
Список 9
<strong> попробуйте </strong> {// Runtimeexception, ioExeption или другие могут быть брошены; // Обратите внимание на разницу между здесь и недопониманием шести, вот часть кода, который бросает несколько исключений. Выше приведено несколько сегментов кода, каждый из которых бросает разные исключения} <strong> Catch </strong> (<strong> Exception </strong> e) {// Как всегда, конвертируйте исключение в Runtimeexception, но E здесь на самом деле является экземпляром Runtimeexception и был инкапсулирован в предыдущий код. Runtimeexception (/**/code,/**/, e);}Если мы преобразуем все исключения в Runtimeexception, как показано в приведенном выше примере, то, когда тип исключения уже является Runtimeexception, мы делаем другую инкапсуляцию. Runtimeexception снова было повторно освоилось, и допустимая информация, переносимая исходным Runtimeexception, была потеряна.
Решение состоит в том, что мы можем добавить соответствующие проверки в класс Runtimeexception, чтобы подтвердить, что добавление параметра не является экземпляром Runtimeexception. Если это так, скопируйте соответствующий атрибут в недавно созданный экземпляр. Или используйте разные блоки операторов Catch, чтобы поймать Runtimeexception и другие исключения. Личный метод предпочтения 1, преимущества являются самоочевидными.
Заблуждение 8: Исключение с многоуровневой печати
Давайте сначала рассмотрим следующий пример, который определяет 2 класса A и B. Код класса B называется в классе A, а также исключения захвата класса A и класса B.
Список 10
<strong> public </strong> <strong> class </strong> <strong> a </strong> {<strong> private </strong> <strong> static </strong> logger logger = loggerfactory.getLogger (a.class); <strong> public </strong> <strong> void </strong> <strong> process </strong> () {<strong> try </strong> {// создание класса B, вы можете изменить другие методы инъекции, такие как b b = <strong> new </strong> b (); b.process (); // Другой код может вызвать исключение} <strong> catch </strong> (xxxexception e) {// Если метод процесса класса B вызовет исключение, исключение будет в B, который напечатан, и он также будет напечатан здесь, поэтому logger.error (e); <strong> throw </strong> <strong> new </strong> runtimeexception (/*код ошибки*/errorcode,/*Информация об исключении*/msg, e); }}} <strong> public </strong> <strong> class </strong> <strong> b </strong> {<strong> private </strong> <strong> static </strong> logger logger = loggerfactory.getLogger (b.class); <strong> public </strong> <strong> void </strong> <strong> process </strong> () {<strong> try </strong> {// код, который может добавить исключение} <strong> catch </strong> (xxxexception e) {logger.error (e); <strong> throw </strong> <strong> new </strong> runtimeexception (/*код ошибки*/errorcode,/*Информация об исключении*/msg, e); }}}То же самое исключение будет напечатано 2 раза. Если уровень немного сложнее, то это головная боль, чтобы не учитывать производительность системы печатных журналов и просто найти конкретные проблемы в журналах исключений.
Фактически, журналы печати требуют только захвата и печати на самом внешнем уровне кода. Печать исключений также может быть написана как AOP и вплетена во внешний слой рамы.
Заблуждение 9: Проблема, которую информация, содержащаяся в исключениях, не может быть полностью найдена
Исключения не только позволяют разработчикам знать, что не так, но чаще всего разработчики также должны знать, что вызывает проблему. Мы знаем, что java .lang.Exception имеет конструктор параметров типа строки, и эта строка может быть настроена на простую для понимания информацию о приглашении.
Простые разработчики пользовательской информации могут только знать, где появляется исключение, но во многих случаях разработчики должны узнать больше о том, какие параметры вызывают такое исключение. В настоящее время нам необходимо добавить информацию о параметрах метода вызова к пользовательской информации. В следующем примере перечислены только случай одного параметра. В случае нескольких параметров вы можете написать класс инструментов для организации такой строки.
Список 11
public <strong>void</strong> retrieveObjectById(Long id){ <strong>try</strong>{ //..some code that throws SQLException }<strong>catch</strong>(SQLException ex){ //Add parameter information to exception information <strong>throw</strong> <strong>new</strong> RuntimeException("Exception <strong>in</strong> retrieveObjectById <strong> с </strong> идентификатором объекта: "+ id, ex); }}Заблуждение 10: не может предсказать потенциальные нарушения
Во время процесса написания кода из -за отсутствия глубокого понимания вызывающего кода невозможно точно определить, будет ли вызываемый код создавать исключения, поэтому обработка игнорируется. После создания производственной ошибки я вспомнил, что я должен добавить исключение извлечения в определенный кусок кода, и я даже не мог точно указать на причину исключения. Это требует, чтобы разработчики не только знали, что они делают, но и знали как можно больше, что сделали другие и какие возможные результаты могут быть вызваны, и для рассмотрения процесса обработки всего приложения с глобальной точки зрения. Эти идеи повлияют на наше написание и обработку кода.
Заблуждение 11: смешанное использование нескольких сторонних библиотек журналов.
В настоящее время существует все больше и больше библиотеки третьих лиц Java. Различные рамки будут представлены в большом проекте, и эти рамки будут зависеть от реализации различных библиотек журналов. Самая проблематичная проблема не в том, чтобы представить все необходимые библиотеки журналов, проблема заключается в том, что введенные библиотеки журналов сами несовместимы. Если на ранней стадии проекта может быть легко решить, вы можете вновь ввести все библиотеки журналов в вашем коде по мере необходимости или изменить рамку. Но такая стоимость недоступна для каждого проекта, и чем больше риск по мере продвижения проекта.
Как мы можем эффективно избежать подобных проблем? Большинство рамок теперь приняли во внимание аналогичные проблемы. Они могут настроить свойства или XML -файлы, параметры или классы реализации журнала сканирования времени выполнения в библиотеке LIB, и только при запуске приложения мы можем определить, какая конкретная библиотека журналов будет применять.
Фактически, основываясь на принципе отсутствия множества уровней печати журнала, мы можем упростить многие классы, которые первоначально назывались кодом печати журнала. Во многих случаях мы можем использовать перехватчики или фильтры для печати журналов для снижения стоимости обслуживания кода и миграции.
Заключение
Вышеуказанное является чисто личным опытом и кратким изложением. Вещи диалектические, и нет абсолютных принципов. Самый эффективный принцип подходит для вас. Я надеюсь, что приведенное выше объяснение и анализ могут быть вам полезны.