Exception during execution что это

ОБРАБОТКА ИСКЛЮЧЕНИЙ В VISUAL C++

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

Эта статья посвящена обработке исключений. В качестве примеров используются языковые конструкции Visual C++ 6.5.

1. Фреймовая обработка исключений

1.1. Исключения и их обработчики

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

Для выполнения описанных выше действий в операционных системах Windows предназначен механизм структурной обработки исключений (structured exception handling, SHE). Работает это так. В программе выделяется блок программного кода, где может произойти исключение. Этот блок кода называется фреймом, а сам код называется охраняемым кодом. После фрейма вставляется программный блок, где обрабатывается исключение. Этот блок называется обработчиком исключения. Когда исключение будет обработано, управление передается первой инструкции, которая следует за обработчиком исключения.

Переменные, объявленные внутри фрейма или блока обработки исключения, являются локальными и видны только внутри соответствующего блока, как это принято в С++. Пример обработки исключения:

1.2. Как получить код исключения

1.3. Функции фильтра

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

Пример программы, в которой используется функция фильтра для принятия решения о дальнейшей обработке исключения, приведён ниже. Здесь функция фильтра (ff) возвращает одно из двух значений EXCEPTION_CONTINUE_EXECUTION или EXCEPTION_EXECUTE_HANDLER. Первое значение возвращается в том случае, если исключение генерируется системой при целочисленном делении на ноль, а второе – в остальных случаях. При попытке деления на ноль происходит исключение и в качестве выражения-фильтра применяется результат выполнения функции ff. Эта функция проверяет, чем было вызвано исключение, и если это деление на ноль, то ошибка исправляется (а = 10). Затем функция возвращает значение EXCEPTION_CONTINUE_EXECUTION, то есть программа продолжает свою работу, но уже с исправленным значением переменной a. Если же это исправление не сделать, то программа войдет в бесконечный цикл.

1.4. Необработанные исключения

1.5. Обработка исключений при операциях с плавающей точкой

По умолчанию система отключает все исключения с плавающей точкой. Поэтому если при выполнении операции с плавающей точкой было получено число, которое не входит в диапазон представления чисел с плавающей точкой, то в результате система вернет NAN или INFINITY в случае слишком малого или слишком большого числа соответственно. Чтобы включить режим генерации исключений с плавающей точкой нужно изменить состояние слова, управляющего обработкой операций с плавающей точкой. Это можно сделать при помощи функции _controlfp, которая имеет следующий прототип: Прототип определен в заголовочном файле float.h. Эта функция возвращает старое слово, управляющее обработкой исключений. Параметр new задает новое управляющее слово, а параметр mask должен принимать значение _MCW_EM. Если значение этого параметра равно 0, то функция возвращает старое управляющее слово.

Ниже приведен пример программы, которая обрабатывает исключение с плавающей точкой при делении на ноль. Все это прекрасно работает в консольных приложениях, а вот добиться нормальной работы обработчика исключений с плавающей точкой в MFC-приложениях мне так и не удалось. Можно, конечно, заменить системный обработчик исключений, как это описано в п.1.4, но тогда программа будет завершаться при возникновении исключения (хотя и не аварийно, то есть без надоевшего всем вопроса Windows XP об отправке отчета в компанию Microsoft). В общем, пришлось мне для обработки исключений с плавающей точкой воспользоваться еще одним способом. Этот способ более трудоемок, зато работает. Хотя во многих случаях проще проверять значения с помощью оператора if, не прибегая к «хитромудрым» способам обработки исключений в Visual C++.

1.6. Использование блоков try и catch

2. Финальная обработка исключений

2.1. Финальные блоки фрейма

В операционных системах Windows существует еще один способ обработки исключений. При этом способе код, где возможно возникновение исключения, также заключается в блок __try. Но теперь за этим блоком следует блок __finally. В таком случае блок __finally выполняется всегда – независимо от того, произошло исключение или нет. Такой способ обработки исключений называется финальная обработка исключений. Структурно финальная обработка выглядит следующим образом: Финальная обработка исключений используется для того, чтобы при любом исходе исполнения блока __try освободить ресурсы (память, файлы и т.п.), которые были захвачены внутри этого блока.

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

2.2. Проверка завершения фрейма

Чтобы определить, как завершился блок __try, используется функция AbnormalTermination, которая имеет следующий прототип: В случае если блок __try завершился ненормально, эта функция возвращает ненулевое значение, иначе – значение FALSE. Используя эту функцию, ресурсы, захваченные в блоке __try, можно освобождать в зависимости от ситуации. Пример:

Источник

Exception Класс

Определение

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

Представляет ошибки, которые происходят во время выполнения приложения.

Примеры

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

Комментарии

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

Ошибки и исключения

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

Ошибки использования. Ошибка использования представляет ошибку в логике программы, которая может привести к исключению. Однако эта ошибка должна быть решена не посредством обработки исключений, но путем изменения неисправного кода. Например, переопределение Object.Equals(Object) метода в следующем примере предполагает, что obj аргумент всегда должен иметь значение, отличное от NULL.

NullReferenceExceptionИсключение, которое возникает, obj Если null можно устранить, изменив исходный код, чтобы явно проверить наличие значения null перед вызовом Object.Equals переопределения, а затем повторной компиляцией. В следующем примере содержится исправленный исходный код, обрабатывающий null аргумент.

Вместо использования обработки исключений для ошибок использования можно использовать Debug.Assert метод для обнаружения ошибок использования в отладочных сборках и Trace.Assert метод для обнаружения ошибок использования в сборках отладки и выпуска. Дополнительные сведения см. в разделе Утверждения в управляемом коде.

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

В некоторых случаях ошибка программы может отражать ожидаемое или предполагаемое состояние ошибки. В этом случае может потребоваться избежать использования обработки исключений для устранения ошибок программы, а затем повторить операцию. Например, если пользователь должен ввести дату в определенном формате, можно выполнить синтаксический анализ строки даты, вызвав DateTime.TryParseExact метод, который возвращает Boolean значение, указывающее, была ли операция анализа успешной, вместо использования DateTime.ParseExact метода, который создает FormatException исключение, если строка даты не может быть преобразована в DateTime значение. Аналогично, если пользователь пытается открыть несуществующий файл, можно сначала вызвать File.Exists метод, чтобы проверить, существует ли файл, и, если он не будет, запрашивать у пользователя, нужно ли его создать.

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

Сбои системы. Сбой системы — это ошибка времени выполнения, которая не может быть обработана программно понятным образом. Например, любой метод может вызвать исключение, OutOfMemoryException Если среда CLR не может выделить дополнительную память. Обычно системные сбои не обрабатываются с помощью обработки исключений. Вместо этого можно использовать событие, например, AppDomain.UnhandledException и вызвать Environment.FailFast метод для регистрации сведений об исключениях и уведомить пользователя об ошибке до завершения работы приложения.

Блоки try/catch

Среда CLR предоставляет модель обработки исключений, основанную на представлении исключений в виде объектов, а также разделении кода программы и кода обработки исключений на try блоки и catch блоки. Может существовать один или несколько catch блоков, каждый из которых предназначен для обработки определенного типа исключений, или один блок, предназначенный для перехвата более конкретного исключения, чем у другого блока.

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

Функции типов исключений

Типы исключений поддерживают следующие функции.

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

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

Свойства класса Exception

Если между двумя или более исключениями существует связь с причинами, InnerException это свойство поддерживает эти сведения. Внешнее исключение создается в ответ на это внутреннее исключение. Код, обрабатывающий внешнее исключение, может использовать сведения из предыдущего внутреннего исключения для более адекватной обработки ошибки. Дополнительные сведения об исключении могут храниться в виде коллекции пар «ключ-значение» в Data свойстве.

Чтобы предоставить пользователю подробные сведения о причине возникновения исключения, HelpLink свойство может содержать URL-адрес (или URN) файла справки.

ExceptionКласс использует COR_E_EXCEPTION HRESULT, имеющий значение 0x80131500.

Список начальных значений свойств для экземпляра Exception класса см. в разделе Exception конструкторы.

Вопросы производительности

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

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

Повторный вызов исключения

Во многих случаях обработчик исключений просто хочет передать исключение в вызывающий объект. Чаще всего это происходит в следующих случаях.

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

для повторного создания исключения рекомендуется просто использовать инструкцию throw в C# и инструкцию throw в Visual Basic без включения выражения. Это гарантирует, что все сведения стека вызовов сохраняются при распространении исключения вызывающему объекту. Это показано в следующем примере. Метод расширения строки ( FindOccurrences ) заключает в оболочку один или несколько вызовов String.IndexOf(String, Int32) без проверки своих аргументов заранее.

Затем вызывающий объект вызывается FindOccurrences дважды. Во втором вызове FindOccurrences вызывающий объект передает в null качестве строки поиска, что приводит к String.IndexOf(String, Int32) созданию ArgumentNullException исключения методом. Это исключение обрабатывается FindOccurrences методом и передается обратно вызывающему объекту. Поскольку оператор throw используется без выражения, выходные данные в примере показывают, что стек вызовов сохранен.

Напротив, если исключение создается повторно с помощью метода

, полный стек вызовов не сохраняется, и в примере создается следующий результат:

Немного более громоздкий альтернативой является вызов нового исключения и сохранение сведений стека вызовов исходного исключения во внутреннем исключении. Затем вызывающий объект может использовать свойство нового исключения InnerException для получения кадра стека и других сведений об исходном исключении. В этом случае оператор Throw будет следующим:

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

Выбор стандартных исключений

В следующей таблице перечислены распространенные типы исключений и условия их создания.

Реализация пользовательских исключений

Определение собственного класса исключений:

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

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

Определите конструкторы класса исключений. Как правило, классы исключений имеют один или несколько следующих конструкторов:

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

Exception(String), который инициализирует новый объект исключения с указанным сообщением об ошибке.

Exception(String, Exception), который инициализирует новый объект исключения с указанным сообщением об ошибке и внутренним исключением.

Exception(SerializationInfo, StreamingContext)— Это protected конструктор, инициализирующий новый объект исключения из сериализованных данных. Этот конструктор следует реализовать, если вы решили сделать объект исключения сериализуемым.

В следующем примере показано использование класса пользовательского исключения. Он определяет NotPrimeException исключение, которое создается, когда клиент пытается получить последовательность простых чисел, указав начальный номер, который не является простым. Исключение определяет новое свойство, NonPrime которое возвращает непростое число, которое привело к исключению. Помимо реализации защищенного конструктора без параметров и конструктора с SerializationInfo параметрами и StreamingContext для сериализации, NotPrimeException класс определяет три дополнительных конструктора для поддержки NonPrime Свойства. Каждый конструктор вызывает конструктор базового класса, а также сохраняет значение непростого числа. NotPrimeException Класс также помечается SerializableAttribute атрибутом.

PrimeNumberGenerator Класс, показанный в следующем примере, использует Сиеве из ератоссенес для вычисления последовательности простых чисел из 2 в предел, заданный клиентом при вызове его конструктора класса. GetPrimesFrom Метод возвращает все простые числа, которые больше или равны указанному нижнему пределу, но выдает исключение, NotPrimeException Если нижний предел не является простым числом.

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

Конструкторы

Инициализирует новый экземпляр класса Exception.

Инициализирует новый экземпляр класса Exception с сериализованными данными.

Инициализирует новый экземпляр класса Exception с указанным сообщением об ошибке.

Инициализирует новый экземпляр класса Exception указанным сообщением об ошибке и ссылкой на внутреннее исключение, вызвавшее данное исключение.

Свойства

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

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

Возвращает или задает HRESULT — кодированное числовое значение, присвоенное определенному исключению.

Возвращает экземпляр класса Exception, который вызвал текущее исключение.

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

Возвращает или задает имя приложения или объекта, вызывавшего ошибку.

Получает строковое представление непосредственных кадров в стеке вызова.

Возвращает метод, создавший текущее исключение.

Методы

Определяет, равен ли указанный объект текущему объекту.

При переопределении в производном классе возвращает исключение Exception, которое является первопричиной одного или нескольких последующих исключений.

Служит хэш-функцией по умолчанию.

При переопределении в производном классе задает объект SerializationInfo со сведениями об исключении.

Возвращает тип среды выполнения текущего экземпляра.

Возвращает объект Type для текущего экземпляра.

Создает неполную копию текущего объекта Object.

Создает и возвращает строковое представление текущего исключения.

События

Возникает, когда исключение сериализовано для создания объекта состояния исключения, содержащего сериализованные данные об исключении.

Источник

Исправляем 7 распространенных ошибок обработки исключений в Java

Привет, Хабр! Представляю вашему вниманию перевод статьи Fixing 7 Common Java Exception Handling Mistakes автора Thorben Janssen.

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

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

Ошибка 1: объявление java.lang.Exception или java.lang.Throwable

Как вы уже знаете, вам нужно либо объявить, либо обработать проверяемое исключение. Но проверяемые исключения — это не единственные, которые вы можете указать. Вы можете использовать любой подкласс java.lang.Throwable в предложении throws. Таким образом, вместо указания двух разных исключений, которые выбрасывает следующий фрагмент кода, вы можете просто использовать исключение java.lang.Exception в предложении throws.

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

Используйте конкретные классы

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

Ошибка 2: перехват обобщенных исключений

Серьезность этой ошибки зависит от того, какой программный компонент вы реализуете, и где вы обнаруживаете исключение. Возможно, было бы хорошо поймать java.lang.Exception в основном методе вашего приложения Java SE. Но вы должны предпочесть поймать определенные исключения, если вы реализуете библиотеку или работаете над более глубокими слоями вашего приложения.

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

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

Ошибка 3: Логирование и проброс исключений

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

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

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

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

Регистрируйте исключение там, где вы его обрабатываете

Таким образом, лучше всего регистрировать исключение тогда, когда вы его обрабатываете. Как в следующем фрагменте кода. Метод doSomething генерирует исключение. Метод doMore просто указывает его, потому что у разработчика недостаточно информации для его обработки. Затем он обрабатывается в методе doEvenMore, который также записывает сообщение журнала.

Ошибка 4: использование исключений для управления потоком

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

Они в основном работают как оператор Go To, потому что они отменяют выполнение блока кода и переходят к первому блоку catch, который обрабатывает исключение. Это делает код очень трудным для чтения.

Они не так эффективны, как общие структуры управления Java. Как видно из названия, вы должны использовать их только для исключительных событий, а JVM не оптимизирует их так же, как и другой код.Таким образом, лучше использовать правильные условия, чтобы разбить свои циклы или инструкции if-else, чтобы решить, какие блоки кода должны быть выполнены.

Ошибка 5: удалить причину возникновения исключения

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

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

Ошибка 6: Обобщение исключений

Когда вы обобщаете исключение, вы ловите конкретный, например, NumberFormatException, и вместо этого генерируете неспецифическое java.lang.Exception. Это похоже, но даже хуже, чем первая ошибка, которую я описал в этой статье. Он не только скрывает информацию о конкретном случае ошибки на вашем API, но также затрудняет доступ.

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

Итак, какой подход лучший?

Будьте конкретны и сохраняйте причину возникновения исключения.

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

Ошибка 7: добавление ненужных преобразований исключений

Как я уже объяснял ранее, может быть полезно обернуть исключения в пользовательские, если вы установите исходное исключение в качестве причины. Но некоторые архитекторы переусердствуют и вводят специальный класс исключений для каждого архитектурного уровня. Таким образом, они улавливают исключение в уровне персистентности и переносят его в MyPersistenceException. Бизнес-уровень ловит и обертывает его в MyBusinessException, и это продолжается до тех пор, пока оно не достигнет уровня API или не будет обработано.

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

Обязательно добавьте информацию

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

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *