Какой объект содержит информацию об ошибке

Учебник по Visual Basic for Applications (VBA). Типы ошибок. Если вы когда-нибудь учились водить автомобиль, то наверняка вспомните, что при первой посадке на водительское сиденье все внимание было приковано к трем деталям: рулю, педалям и рычагу переключения передач. Происходящее вне автомобиля уходило на второй план, так как вначале нужно было стронуться с места. По мере практики навыки вождения улучшались и эти три детали постепенно уходили на задний план. Как ни странно, но руль и рычаг переключения передач всегда оказывались там, куда вы не смотря протягивали руки, а ноги сами находили педали. Теперь все внимание стало занимать происходящее на дороге. Иными словами, вы стали опытным водителем.

Обработка ошибок

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

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

Типы ошибок

Существуют три типа ошибок в программе:

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

Инструкция On Error

Ошибки времени выполнения можно перехватывать внутри подпрограммы. Для этого используется инструкция On Error, которая имеет три формата:

  • On Error GoTo <Метка> — при возникновении ошибки управление передается инструкции, помеченной меткой <Метка>. Метка должна быть допустимым идентификатором, к которому предъявляются такие же требования как и к переменным. Внутри подпрограммы метка указывается в самом начале помечаемой строки и после метки ставится двоеточие. В качестве примера создадим функцию для деления двух целых чисел. Внутри функции предусмотрим обработку ошибки деления на 0:
Function Деление(x As Integer, y As Integer) As Double
   On Error GoTo ПриОшибке
   Деление = x / y
   Exit Function
ПриОшибке:
   Деление = 0
End Function

Если при вызове функции во втором параметре передать значение 0, то управление будет передано в строку, помеченную с помощью метки ПриОшибке. Обратите внимание на то, что метка расположена после инструкции Exit Function. В этом случае код после инструкции Exit Function будет выполнен только в том случае, если возникнет ошибка;

  • On Error Resume Next — при возникновении ошибки управление передается следующей инструкции;
  • On Error GoTo 0 — отключает перехват ошибок.

Если внутри подпрограммы не предусмотрен перехват ошибки, то при возникновении ошибки работа программы прерывается и выводится стандартное окно с описанием и несколькими кнопками: Continue (продолжить), End (завершить выполнение программы), Debug (перейти в режим отладки) и Help (вывод справки).

Инструкция Resume

Инструкция Resume позволяет указать куда следует переходить после обработки ошибки. Инструкция имеет несколько форматов:

  • Resume [0] — управление передается инструкции, вызвавшей ошибку;
  • Resume Next — управление передается инструкции, следующей за инструкцией, вызвавшей ошибку;
  • Resume <Метка> — управление передается инструкции, помеченной меткой <Метка>.

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

Получение информации об ошибке и генерация ошибки

Вся информация о последней ошибке доступна через объект Err. Объект содержит следующие свойства:

  • Number — код ошибки, например, код 11 для ошибки деления на 0. Если ошибки не произошло, то свойство содержит значение 0;
  • Description — описание ошибки, например, строка "Division by zero" для ошибки деления на 0. Пример вывода кода и описания ошибки:
Debug.Print Err.Number; Err.Description
  • Source — название текущего проекта;
  • HelpFile — путь к файлу справки;
  • HelpContext — идентификатор раздела в справочном файле;
  • LastDLLError — системный код ошибки при работе с DLL.

Объект Err содержит следующие методы:

  • Clear() — очищает всю информацию о последней ошибке. Этот метод следует вызвать после успешной обработки ошибки. Информация об ошибке автоматически очищается при выходе из подпрограммы и ряде других случаев;
  • Raise() — позволяет сгенерировать ошибку в программе. Формат метода:
Raise Number[, Source][, Description][, HelpFile][, HelpContext]

В параметре Number указывается код генерируемой ошибки (целое число от 0 до 65 535). Коды от 0 до 512 зарезервированы под системные ошибки, а остальные коды можно использовать под пользовательские ошибки. Чтобы сгенерировать ошибку с пользовательским кодом необходимо сложить код с константой vbObjectError. Остальные параметры являются необязательными и полностью аналогичны одноименным свойствам объекта Err. Пример генерации и обработки пользовательской ошибки:

Sub ГенерацияОшибки()
   On Error GoTo ПриОшибке
   Err.Raise vbObjectError + 513
   Exit Sub
ПриОшибке:
   Debug.Print Err.Number; Err.Description
   ' -2147220991 Automation error
End Sub

Способы поиска ошибок в программе

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

Первое, на что следует обратить внимание, — на объявления переменных. Например, рассмотрим простой пример:

Как вы думаете, какое значение отобразится в окне Immediate после выполнения этого кода? Думаете, что число 10? Не факт! Вот тут-то и кроется проблема не видная на первый взгляд. В первой инструкции присваивается значение переменной x, имя которой набрано на английской раскладке клавиатуры, а вот во второй инструкции выводится значение переменной x, имя которой набрано на русской раскладке клавиатуры. В результате значение присваивается одной переменной, а выводится значение другой переменной. Такие ситуации очень часто встречаются в программах на языке VBA, так как объявлять переменную не обязательно. Чтобы избежать такой ситуации следует обязательно объявлять переменные явным образом. Контроль за соблюдением этого правила можно возложить на компилятор, добавив в начале модуля следующую инструкцию:

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

Option Explicit
...
Dim x As Integer
x = 10
Debug.Print x ' 10

Далее следует обратить внимание на форматирование кода. Начинающие программисты обычно не обращают на это никакого внимания, считая этот процесс лишним. А на самом деле зря! Компилятору абсолютно все равно, разместите вы все инструкции на одной строке или выполните форматирование кода. Однако, при поиске ошибок форматирование кода позволит найти ошибку гораздо быстрее.

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

Dim Массив As Variant, i As Integer, j As Integer
Массив = Array(Array(0, 1), Array(2, 3), Array(4, 5))
For i = 0 To 2
   For j = 0 To 1
      Debug.Print Массив(i)(j)
   Next
Next

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

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

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

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

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

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

Проверить значение константы позволяет следующая конструкция:

#If MY_DEBUG Then
   ' Здесь размещаем инструкции вывода значений
#End If

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

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

Прежде чем начать отладку необходимо пометить строки внутри программы с помощью точек останова. Для добавления точки останова делаем строку активной, а затем из меню Debug выбираем пункт Toggle Breakpoint. Слева от строки появится кружок, обозначающий точку останова. Добавить точку останова можно еще быстрее. Для этого достаточно щелкнуть слева от строки левой кнопкой мыши. Повторный щелчок позволяет удалить точку останова. Кроме того, для добавления или удаления точки отстанова можно воспользоваться клавишей <F9>. Чтобы удалить все точки останова следует из меню View выбрать пункт Clear All Breakpoints.

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

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

При отладке можно контролировать значения отдельных переменных, а не всех сразу. Для этого следует выделить название переменной и из меню Debug выбрать пункт Add Watch. Можно также выделить название переменной и из контектного меню выбрать пункт Add Watch. В открывшемся окне устанавливаем флажок Watch Expression и нажимаем кнопку OK. Значение переменной будет отображаться в окне Watches. Чтобы отобразить окно Watches из меню View выбираем пункт Watch Window. Чтобы отменить отслеживание нужно выделить строку в окне Watches и нажать клавишу <Delete>.

Для пошагового выполнения программы предназначены следующие пункты в меню Debug или соответствующие кнопки на панели инструментов Debug (View | Toolbars | Debug):

  • Step Into (клавиша <F8>) — выполняет переход к следующей инструкции;
  • Step Over — выполняет одну инструкцию. Если в этой инструкции производится вызов подпрограммы, то подпрограмма выполняется за один шаг и отладчик переходит в режим ожидания после выхода из подпрограммы;
  • Step Out — при заходе в подпрограмму этот пункт позволяет выполнить подпрограмму за один шаг и выйти из нее. Отладчик переходит в режим прерывания после выхода из подпрограммы;
  • Run To Cursor — выполняет переход к инструкции, в которой расположен курсор.

Если необходимо посмотреть последовательность вызова подпрограмм, то следует открыть окно Call Stack, выбрав в меню View пункт Call Stack.

Подача звукового сигнала

При возникновении ошибки или при неправильном вводе данных имеет смысл привлечь внимание пользователя звуковым сигналом. Сгенерировать звуковой сигнал позволяет инструкция Beep. Пример:

Dim Результат
Beep
Результат = InputBox("Необходимо ввести значение")

Visual Basic for Applications (VBA)
Статьи по Visual Basic for Applications (VBA)

Цикл статей «Учебник Java 8».

Следующая статья — «Java 8 потоки ввода/вывода».
Предыдущая статья — «Java 8 обобщения».

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

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

Когда возникает какая-нибудь ошибка внутри метода, метод создаёт специальный объект, называемый объектом-исключением или просто исключением (exception object), который передаётся системе выполнения. Этот объект содержит информацию об ошибке, включая тип ошибки и состояние программы, в котором произошла ошибка. Создание объекта-исключения и передача его системе выполнения называется броском исключения (throwing an exception).

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

Выбранный обработчик исключения ловит это исключение.

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

В Java все классы-исключения являются наследниками от класса
java.lang.Throwable, который в свою очередь имеет подклассы
java.lang.Error  и
java.lang.Exception. Класс
java.lang.Exception  имеет дочерний класс
java.lang.RuntimeException.

java.lang.Throwable java.lang.Exception java.lang.Error java.lang.RuntimeException

Согласно соглашению все бросаемые исключения являются наследниками трёх классов:
java.lang.Error ,
java.lang.Exception  или
java.lang.RuntimeException. Технически можно бросить исключение, которое не является наследником этих трёх классов, но является наследником
java.lang.Throwable, но так делать не принято.

Из описанных выше трёх классов выходит три вида исключений в Java:

  • Наследники
    java.lang.Error. Эти исключения возникают при серьёзных ошибках, после которых невозможно нормальное продолжение выполнения программы. Это могут быть различные сбои аппаратуры и т. д. В обычных ситуациях ваш код не должен перехватывать и обрабатывать этот вид исключений.
  • Наследники
    java.lang.RuntimeException. Это непроверяемый тип исключений вроде выхода за границу массива или строки, попытка обращения к методу на переменной, которая содержит
    null, неправильное использование API и т. д. В большинстве своём программа не может ожидать подобные ошибки и не может восстановиться после них. Подобные исключения возникают из-за ошибок программиста. Приложения может их перехватывать, но в большинстве случаев имеет гораздо больше смысла исправить ошибку, приводящую к подобным исключениям.
  • Наследники
    java.lang.Exception, которые НЕ являются наследниками
    java.lang.RuntimeException. Подобный тип исключений называется проверяемыми исключениями (checked exceptions). Это такой тип исключений, который может ожидать хорошо написанная программа, и из которых она может восстановить свой обычный ход выполнения. Это может быть попытка открыть файл, к которому нет доступа, или которого не существует, проблемы с доступом по сети и т. д. Все исключения являются проверяемыми, кроме наследников
    java.lang.Error  и
    java.lang.RuntimeException. Любой метод, который может бросить проверяемое исключение, должен указать это исключение в клаузе
    throws. Для любого кода, который может бросить проверяемое исключение, это исключение должно быть указано в
    throws  метода, либо должно быть перехвачено с помощью инструкции
    trycatch.

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

Рассмотрите следующий код:

import java.io.*;

class Main {

    public static void main(String[] args) {

        byte[] bytesToWrite = new byte[100];

        OutputStream os = new FileOutputStream(«output.file»);

        os.write(bytesToWrite);

        os.close();

    }

}

На текущий момент этот код не будет компилироваться, так как конструктор
FileOutputStream(String name)  может бросать проверяемое исключение
FileNotFoundException, вызов метода
os.write(byte[] b)  может бросать проверяемое исключение
IOException, и вызов метода
os.close()  тоже может бросать проверяемое исключение.

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

public FileOutputStream(String name)

                 throws FileNotFoundException

public void write(byte[] b) throws IOException

public void close()

           throws IOException

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

Чтобы пример выше компилировался, нужно весь код, который может бросить исключения поместить в блок
try:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import java.io.*;

class Main {

    public static void main(String[] args) {

        byte[] bytesToWrite = new byte[100];

        try {

            OutputStream os = new FileOutputStream(«output.file»);

            os.write(bytesToWrite);

            os.close();

        } catch (FileNotFoundException fnfe) {

            System.out.println(«Cannot find the file.»);

        } catch (IOException ioex) {

            System.out.println(«Error writing file: « + ioex.getMessage());

        }

    }

}

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

catch (FileNotFoundException fnfe) {

    System.out.println(«Cannot find the file.»);

}

Этот блок выведет в консоль строку “Cannot find the file”, после чего управление передастся на следующую инструкцию за блоком
trycatch.

Если же возникнет исключение
IOException  либо один из его потомков (
FileNotFoundException  тоже является потомком
IOException, но поскольку мы указали его блок первым, то в случае
FileNotFoundException  будет выполняться его, специфичный блок), то будет выполняться блок, который выведет в консоль строку “Error writing file: …”, после чего управление передастся на следующую инструкцию за блоком
trycatch.

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

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

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

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

catch (IOException|SQLException ex) {

    logger.log(ex);

    // … other code

}

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

Посмотрим ещё раз на фрагмент кода из примера:

OutputStream os = new FileOutputStream(«output.file»);

os.write(bytesToWrite);

os.close();

Последняя строка
os.close()  закрывает файл и освобождает ресурсы системы. Но она сработает только при нормальном ходе выполнения программы. Если какое-нибудь исключение возникнет в конструкторе или в методе
write(), то метод закрытия потока не выполнится, а значит будет утечка ресурсов.

Чтобы избежать подобных проблем освобождение ресурсов нужно осуществлять в блоке
finally. Код в блоке
finally  выполняется ВСЕГДА после завершения блока
try, даже в случае возникновения исключения.

Исправленный код:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

import java.io.*;

class Main {

    public static void main(String[] args) {

        byte[] bytesToWrite = new byte[100];

        OutputStream os = null;

        try {

            os = new FileOutputStream(«output.file»);

            os.write(bytesToWrite);

            System.out.println(«end try»);

        } catch (FileNotFoundException fnfe) {

            System.out.println(«Cannot find the file.»);

        } catch (IOException ioex) {

            System.out.println(«Error writing file: « + ioex.getMessage());

        } finally {

            System.out.println(«finally.»);

            if (os != null) {

                // Метод close тоже может бросить

                // исключение.

                try {

                    os.close();

                } catch (IOException closeException) {

                    System.out.println(«closeException: «

                            + closeException.getMessage());

                }  

            }

        }

        System.out.println(«End of program.»);

    }

}

При обычном ходе выполнения этот код выведет в консоль следующее:

end try

finally.

End of program.

Если же во время открытия файла на запись произойдёт ошибка, то вывод может стать таким:

Cannot find the file.

finally.

End of program.

Как видите блок
finally  отработал после блока обработки исключений.

Если виртуальная машина Java завершит своё выполнение во время выполнения кода
try  или
catch, то блок
finally  может НЕ выполниться. Так же если поток будет прерван внутри кода
try  или
catch, то блок
finally  может НЕ выполниться, хотя программа продолжит своё выполнение.

Приведённый выше код можно сделать более понятным, если использовать оператор
trywithresources. Любой объект, который реализует интерфейс
java.lang.AutoCloseable, который включает все объекты, который реализуют
java.io.Closeable (
Closeable  расширяет
AutoCloseable), например
FileOutputStream , можно использовать в
trywithresources:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import java.io.*;

class Main {

    public static void main(String[] args) {

        byte[] bytesToWrite = new byte[100];

        try (OutputStream os = new FileOutputStream(«output.file»)) {

            os.write(bytesToWrite);

            System.out.println(«end try»);

        } catch (FileNotFoundException fnfe) {

            System.out.println(«Cannot find the file.»);

        } catch (IOException ioex) {

            System.out.println(«Error writing file: « + ioex.getMessage());

        }

        // Блок finally уже не нужен, но можно использовать, если хочется.

        System.out.println(«End of program.»);

    }

}

В этом примере
trywithresources  автоматически вызовет метод
close() , что освободит ресурсы.

В блоке
trywithresources  можно указывать несколько ресурсов, тогда они будут открываться слева направо, как указано в блоке, а закрываться справа налево (то есть в обратном порядке):

try (OutputStream os = new FileOutputStream(«output.file»); FileReader fr = new FileReader(«input.txt»)) {

    // …

}

Блок
trywithresources  может не иметь ни секции
catch , ни
finally , но обычный блок
try  должен обязательно иметь либо секцию
catch, либо секцию
finally, либо обе секции.

Ресурсы блока
trywithresources  закрываются перед выполнением блоков
catch  и
finally.

Рассмотрите следующий код:

static String readFirstLineFromFileWithFinallyBlock(String path)

                                                     throws IOException {

    BufferedReader br = new BufferedReader(new FileReader(path));

    try {

        return br.readLine();

    } finally {

        if (br != null) br.close();

    }

}

Если метод
readLine()  бросит исключение, а затем метод
close()  тоже бросит исключение, то метод
readFirstLineFromFileWithFinallyBlock()  бросит исключение из блока
finally , а исключение из блока
try  будет подавлено.

Если же исключение возникнет в блоке
try  и в блоке освобождающем ресурсы для
trywithresources, то конечное исключение, бросаемое методом будет исключение из блока
try, то есть исходное. Это ещё одно преимущество использования
trywithresources. Исключения, которые были подавлены в блоке
trywithresources  можно получить с помощью метода
public final Throwable[] getSuppressed().

Метод
close()  в интерфейсе
java.lang.AutoCloseable  объявляет в клаузе
throws  исключение
Exception, а метод
close()  в 
java.io.Closeable  объявляет
IOException, что позволяет наследникам
AutoCloseable  определять свои, специфичные для своей области исключения.

Указание типов исключений, бросаемых методом

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

class WildWorld {

    public void someCalculation(int arg1, double arg2)

            throws java.io.IOException, java.sql.SQLException,

                    java.lang.IndexOutOfBoundsException {

    }

}

Исключение
IndexOutOfBoundsException  является наследником
RuntimeException, поэтому указывать его не обязательно и даже не нужно:

class WildWorld {

    public void someCalculation(int arg1, double arg2)

            throws java.io.IOException, java.sql.SQLException {

    }

}

Как бросить исключение

Перед тем как вы сможете перехватить исключение, какой-нибудь код должен его бросить/сгенерировать. Любой код может бросить исключение: ваш код, код из пакета, написанного кем-то другим, сама среда Java. Исключение всегда бросается с помощью инструкции
throw , независимо от того, кто его бросает:

throw someThrowableObject;

Пример:

if (x == 0)

    throw new IllegalStateException(«Что-то пошло не так»);

Цепочки исключений

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

Следующие методы и конструкторы класса
java.lang.Throwable  помогают работать с цепочками исключений:

Throwable getCause()

Throwable initCause(Throwable)

Throwable(String, Throwable)

Throwable(Throwable)

Аргумент
Throwable  метода
initCause  и
Throwable  в конструкторах — это исключения, которые привели к текущему исключению. Метод
getCause()  возвращает исключение, которое стало причиной текущего исключения, а метод
initCause  устанавливает причину текущего исключения:

Пример использования цепочки исключений:

try {

} catch (IOException e) {

    throw new SampleException(«Other IOException», e);

}

В этом примере при обработке исключения
IOException  создаётся новое исключение
SampleException, а причина этого исключения присоединяется к цепочке исключений, и цепочка исключений бросается в следующий уровень обработчиков исключений.

Если какой-нибудь код с верхнего уровня обработчиков исключений захочет вывести стек вызовов, то ему нужно будет использовать метод
getStackTrace():

catch (Exception cause) {

    StackTraceElement elements[] = cause.getStackTrace();

    for (int i = 0, n = elements.length; i < n; i++) {      

        System.err.println(elements[i].getFileName()

            + «:» + elements[i].getLineNumber()

            + «>> «

            + elements[i].getMethodName() + «()»);

    }

}

Создание своих объектов-исключений

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

Вам следует написать свои собственные классы исключений, если вы ответите «Да» на любой из следующих вопросов, в противном случае вам, вероятно, следует использовать какое-нибудь из существующих исключений:

  • Вам нужно исключение типа, который не предоставлен платформой Java?
  • Поможет ли это пользователям, если они смогут отличать ваши исключения от исключений, брошенных другими производителями?
  • Бросает ли ваш код более одного связанного исключения?
  • Если вы используете чьи-то другие исключения, то смогут ли пользователи получить доступ к этим исключениям? Или должен ли быть пакет независимым и самодостаточным?

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

ownexceptions

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

Согласно соглашению о кодировании в Java имена исключений должны заканчиваться на
Exception.

Пример возможного кода для исключения
GameLogicException:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

public class GameLogicException extends Exception {

    // Конструкторы, вызывающие конструкторы базового класса.

    public GameLogicException() {

        super();    

    }

    public GameLogicException(String message) {

        super(message);

    }

    public GameLogicException(String message, Throwable cause) {

        super(message, cause);

    }

    public GameLogicException(Throwable cause) {

        super(cause);

    }

    // остальные методы.    

}                    

Преимущества исключений

  1. Разделение кода обработки ошибок от обычного кода.
  2. Распространение информации о произошедшей ошибке вверх по стеку вызовов.
  3. Группировка и разделение различных типов ошибок.

Цикл статей «Учебник Java 8».

Следующая статья — «Java 8 потоки ввода/вывода».
Предыдущая статья — «Java 8 обобщения».

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

Давайте разберемся,
что значит «возникла ошибка»? Точнее
следует говорить возбуждена (raise) ошибка.
Кто обнаруживает ошибку? Обнаружение
исключительной ситуации и возбуждение
ошибки может быть сделано самой
операционной системой (VBA) или исполняемой
процедурой. Ошибки, возбуждаемые
операционной системой, могут быть
следствием аппаратных прерываний,
например, из-за деления на ноль, вычисления
корня из отрицательного числа, но это
могут быть и ошибки, программно
обнаруживаемые операционной системой,
например, при попытке открыть несуществующий
файл. Все эти ошибки будем называть
системными или внутренними ошибками
VBA. Все они тщательно классифицированы
и каждая из них однозначно идентифицируется
своим номером. Другую группу ошибок
составляют собственные или пользовательские
ошибки, возбуждение которых предусматривает
программист. Например, при работе с
объектом пользовательского класса
программист может и должен предусмотреть
специальную процедуру Check,
которая проверяет правильность задания
свойств объекта. Если обнаруживается,
что свойства объекта заданы некорректно,
так что выполнение операций над ним
приведет к неверным результатам, то
возбуждается собственная ошибка.
Конечно, также как и для стандартных
ошибок, ее тип должен быть полностью
определен, задан ее номер и другие
параметры. Возможно, программное
обнаружение исключительных ситуаций
и возбуждение собственных ошибок это
наиболее важная и наиболее трудная
часть программистской работы по
управлению ошибками. Заметим, что какие
бы ошибки не возбуждались, — внутренние
или пользовательские, в момент возбуждения
ошибки заполняются свойства объекта
Err,
так что он содержит всю информацию о
последней возникшей ошибке.

Синтаксически
охраняемый блок окружен специальными
операторами On
Error. В начале
блока оператор On
Error задает
метку обработчика ошибки охраняемого
блока. Обработчик ошибок, как правило,
завершается специальным оператором
Resume,
который задает точку в процедуре, которой
передается управление после завершения
обработки ошибки. Приведем схему
процедуры с тремя охраняемыми блоками:

Sub
ProcWithErrors()

‘Первый
охраняемый блок

On
Error GoTo ErrHadler1 ‘ подключение 1-го обработчика
ошибок


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

On
Error GoTo 0 отключение 1-го обработчика
ошибок

‘Второй
охраняемый блок

On
Error GoTo ErrHadler2 ‘ подключение 2-го обработчика
ошибок


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

On
Error GoTo 0 отключение 2-го обработчика
ошибок

‘Третий
охраняемый блок

On
Error GoTo ErrHadler3 ‘ подключение 3-го обработчика
ошибок


Третья часть процедуры, которая может
вызвать ошибку.

On
Error GoTo 0 отключение 3-го обработчика
ошибок

RepeatPoint: ‘
точка, с которой возобновляется выполнение

‘после
обработки ошибки в 3-ей части

Exit
Sub ‘выход из процедуры при отсутствии
ошибок

‘ОбработкаОшибок:

ErrHandler1:


1-ый обработчик ошибок

Resume ‘возврат
к оператору, вызвавшему ошибку в 1-ой
части

ErrHandler2:


2-ой обработчик ошибок

Resume
Next ‘переход к оператору, следующему за
оператором

‘вызвавшим
ошибку во 2-ой части

ErrHandler3:


3-ий обработчик ошибок

Resume
RepeatPoint ‘переход к строке, с которой
возобновляется

‘выполнение
после обработки ошибки в 3-ей части

End
Sub

Пример
10.2. (html,
txt)

Такова общая,
достаточно простая схема обработки
ошибок (исключений) в языке VBA. Стоит
обратить внимание на то, что ситуация
все же не столь проста, как может
показаться с первого взгляда. Дело в
том, что любой охраняемый блок может
содержать вызовы процедуры процедур и
функций. Поэтому реальная ситуация
обычно такова, — один из операторов
охраняемого блока запускает цепочку
вызовов процедур и функций, каждая из
которых имеет свои охраняемые блоки и
свои обработчики ошибок. Ошибка может
произойти на каком-то шаге в одной из
вызванных процедур. Какие обработчики
будут вызываться и в каком порядке, об
этом поговорим чуть позже. Чтобы
разобраться с деталями, вначале стоит
подробно рассмотреть возможности
используемых средств — операторов On
Error, Resume
и объекта Err
с его свойствами и методами.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

16 / 16 / 0

Регистрация: 10.09.2012

Сообщений: 113

1

17.12.2012, 16:13. Показов 34014. Ответов 9


Информация из интернета:

Ошибки в VBA можно разделить:

Кликните здесь для просмотра всего текста

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

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

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

Синтаксически охраняемый блок окружен специальными операторами On Error.

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

Схема процедуры с тремя охраняемыми блоками (разные варианты обработки ошибок):

Кликните здесь для просмотра всего текста

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Sub ProcWithErrors()
        'Первый охраняемый блок
                On Error GoTo ErrHadler1        ' подключение 1-го обработчика ошибок
                        ' Первая часть процедуры, которая может вызвать ошибку.
                        ...
                On Error GoTo 0 отключение 1-го обработчика ошибок
 
        'Второй охраняемый блок
                On Error GoTo ErrHadler2        ' подключение 2-го обработчика ошибок
                        ' Вторая часть процедуры, которая может вызвать ошибку.
                        ...
                On Error GoTo 0 отключение 2-го обработчика ошибок
 
        'Третий охраняемый блок
                On Error GoTo ErrHadler3        ' подключение 3-го обработчика ошибок
                        ' Третья часть процедуры, которая может вызвать ошибку.
                        ...
                On Error GoTo 0 отключение 3-го обработчика ошибок
 
                RepeatPoint:            ' точка, с которой возобновляется выполнение
                        'после обработки ошибки в 3-ей части
                        ...
 
                Exit Sub                'выход из процедуры при отсутствии ошибок
                'ОбработкаОшибок:
                ErrHandler1:    
                        ' 1-ый обработчик ошибок
                        ...
                        Resume  'возврат к оператору, вызвавшему ошибку в 1-ой части
 
                ErrHandler2:    
                        ' 2-ой обработчик ошибок
                        ...
                        Resume Next     'переход к оператору, следующему за оператором 
                        'вызвавшим ошибку во 2-ой части
 
                ErrHandler3:    
                        ' 3-ий обработчик ошибок
                        ...
                        Resume RepeatPoint      'переход к строке, с которой возобновляется
                        'выполнение после обработки ошибки в 3-ей части
End Sub

Варианты комбинаций операторов On Error и Resume:

Кликните здесь для просмотра всего текста


On Error GoTo строка;
On Error Resume Next;
On Error GoTo 0;
On Error Resume (или On Error Resume (0) )

On Error GoTo строка — управление покидает охраняемый блок и передается на указанную строку, запуская, тем самым, обработчик ошибок, начинающийся в этой строке.

On Error Resume Next — такая ситуация разумна, когда вслед за оператором, при выполнении которого потенциально возможна ошибка,помещается оператор, анализирующий объект Err.

On Error GoTo 0 -он завершает охраняемый блок. Оператор можно опускать, если охраняемый блок завершается вместе с самой процедурой.

On Error Resume (или On Error Resume (0) ) — выполнение программы продолжается с повторного выполнения оператора, вызвавшего ошибку.
Используется,например, когда ошибка вызвана вводом неверных данных пользователем, а в обработчике ошибок у него запрашиваются новые правильные данные.

Объект Err

Кликните здесь для просмотра всего текста

Объект Err содержит информацию о последней ошибке выполнения.
Объект Err создается системой вместе с проектом.
Очистка объекта Err может производиться принудительно (использование метода Clear): Err.Clear

Автоматическая очистка

свойств объекта Err происходит также при выполнении операторов:

оператора Resume любого вида;
Exit Sub, Exit Function, Exit Property ;
оператора On Error любого вида.

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



4



Понравилась статья? Поделить с друзьями:

Читайте также:

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

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии