
- •Программирование на Java Тема 4.1 Обработка исключительных ситуаций
- •Исключительные ситуации
- •Исключительные ситуации
- •Исключительные ситуации
- •Классы исключений
- •Классы исключений
- •Классы исключений
- •Классы исключений
- •Описание исключительной ситуации
- •Описание исключительной ситуации
- •Множественный блок catch{}
- •Множественный блок catch{}
- •Вложенные блоки try
- •Вложенные блоки try
- •Вложенные блоки try
- •Вложенные блоки try
- •Генерирование исключений
- •Генерирование исключений
- •Генерирование исключений
- •Выбрасывание исключений методами
- •Выбрасывание исключений методами
- •Выбрасывание исключений методами
- •Контролируемые и неконтролируемые исключения
- •Контролируемые и неконтролируемые исключения
- •Контролируемые и неконтролируемые исключения
- •Создание собственных исключений
- •Создание собственных исключений
- •Создание собственных исключений
- •Создание собственных исключений
- •Создание собственных исключений

Множественный блок catch{}
• Пример 4. Несколько блоков catch
11

Множественный блок catch{}
Для каждого типа исключений можно предусмотреть свой блок catch для обработки. Блоки размещаются один за другим и им передаются разные аргументы (объекты исключений разных классов) в соответствии с типом обрабатываемой исключительной ситуации.
На слайде приведен пример программы, в которой помимо ошибки деления на ноль обрабатывается также и ошибка неверной индексации массива.С помощью команды Random r=new Random() создается объект r для генерирования случайных чисел. Кроме того, создается целочисленный массив MyArray из двух элементов (значения 0 и 2), также описываются две целочисленные переменные a и b.
В цикле командой a=r.nextInt(3) присваивается значение переменной a — случайное целое число в диапазоне от 0 до 2 включительно. Далее командой b=10/MyArray[a] присваивается значение переменной b. При выполнении этой команды могут возникать неприятности двух видов. Во- первых, если значение переменой a равно 0, то выполняется деление на ноль, поскольку элемент массива MyArray[0] равен нулю. Во-вторых, если значение переменой a равно 2, то имеет место ошибка выхода за границы массива, поскольку элемента MyArray[2] не существует. Если же значение переменной a равно 1, то значение переменной b вычисляется как 5 и выводится на экран командой System.out.println(b).
Для обработки ошибки деления на ноль используется блок catch с объектом класса ArithmeticException. В этом случае выводится сообщение о том, что произошла попытка деления на ноль.
Исключительная ситуация, связанная с неправильной индексацией элементов массива, описывается исключением класса ArrayIndexOutOfBoundsException. Объект этого класса передается во второй блок catch. Обработка этой ошибки сводится к тому, что выводится сообщение о выходе за границы массива.
Наконец, блок finally содержит команду вывода разделительной «звездной линии», которая отображается независимо от того, произошла какая-либо ошибка или нет. Результат выполнения программы представлен на слайде.
12

Вложенные блоки try
• Пример 5. Вложенные блоки try
13

Вложенные блоки try
Один блок try может размещаться внутри другого блока try. В этом случае, если во внутреннем блоке try возникает ошибка и этот блок try не содержит блока catch для ее обработки, исключение выбрасывается во внешний блок try и начинается последовательный просмотр его блоков catch на предмет обработки возникшей ошибки.
Может сложиться и более нетривиальная ситуация, например, когда метод, который вызывается в блоке try, сам содержит блок try. Если в блоке try метода возникает ошибка, не обрабатываемая методом, ее перехватывает внешний блок try, в котором вызывается метод.
Общий принцип обработки ситуаций при сложной схеме включения блоков try состоит в том, что при входе в очередной блок try контексты обрабатываемых этим блоком исключений записываются в стек. При возникновении ошибки этот стек начинает «раскручиваться» — контексты исключений просматриваются в обратном порядке (то есть последний занесенный в стек контекст
исключения просматривается первым).
В листинге на слайде приведен пример использования вложенных блоков try.
Как и ранее, в программе генерируются случайные числа (с помощью объекта r класса Random), объявляются две целочисленные переменные a и b, а также целочисленный массив c, состоящий всего из двух элементов (со значениями –1 и 1).
В цикле внешнего блока try последовательное выполнение команд a=r.nextInt(3) и b=100/a может закончиться генерированием исключения, поскольку среди возможных значений переменной a есть и нулевое, что, в свою очередь, означает ошибку деления на ноль. На этот случай предусмотрен блок catch внешнего блока try. В случае ошибки выполняется команда: System.out.println("Деление на ноль: "+e). Здесь объект e класса ArithmeticException является аргументом блока catch.
Если в указанном месте программы ошибка деления на ноль не возникает, значение переменной b выводится на экран (эта переменная может принимать всего два значения: 100 при значении переменной a равном 1 и 50 при значении переменной a равном 2), после чего выполняется серия команд, заключенных во внутренний блок try.
14

Вложенные блоки try
• Пример 5. Вложенные блоки try
15

Вложенные блоки try
Сразу отметим, что этот блок обрабатывает только исключение, связанное с выходом за границы массива (объект класса ArrayIndexOutOfBoundsException). В случае возникновения соответствующей ошибки выполняется команда: System.out.println("Выход за границы массива: "+e).
Что касается самого программного кода во внутреннем блоке try, то он может вызывать исключения двух типов. В частности, там с помощью условной инструкции проверяется условие равенства значения переменной a единице. Если условие соблюдается, то при выполнении команды a=a/(a-1) происходит ошибка деления на ноль. В противном случае (то есть если значение переменной a отлично от единицы) выполняется команда c[a]=200. Обращаем внимание, что внутренний блок try выполняется, только если значение переменной a равно 1 или 2, поскольку если значение этой переменной равно 0, еще раньше возникнет ошибка деления на ноль, которая перехватывается блоком catch внешнего блока try. Поэтому если во внутреннем блоке try значение переменной a отлично от единицы, это автоматически означает, что значение переменной a равно 2.
В результате при выполнении команды c[a]=200 возникает ошибка выхода за границы массива, поскольку в массиве c всего два элемента, а элемента c[2] там просто нет.
Таким образом, во внутреннем блоке try обрабатывается ошибка выхода за границы диапазона. Если во внутреннем блоке try возникает ошибка деления на ноль, она обрабатывается блоком catch внешнего блока try. Результат выполнения программы примера 5 представлен на слайде.
16

Генерирование исключений
Команда генерирования исключения:
throw объект_исключения;
• Пример 6. Явное выбрасывание исключения
17

Генерирование исключений
Для генерирования исключения используется ключевое слово throw. После инструкции throw необходимо указать объект исключения, то есть объект, описывающий создаваемую исключительную ситуацию. Причем предварительно этот объект нужно создать. Напомним, что объект исключения — это объект класса Throwable или его подкласса. Существует два способа создания объекта исключения. Во-первых, можно воспользоваться аргументом блока catch, во- вторых, можно создать новый объект с помощью оператора new. При этом прибегают к помощи конструктора класса соответствующего исключения. Все исключения времени выполнения программы (класса RuntimeException) имеют конструкторы без аргументов и с текстовым аргументом. В последнем случае текст, переданный конструктору при создании объекта, отображается затем при описании объекта, если последний приводится к текстовому формату (например, при передаче объекта методам print() и println()).
После выполнения оператора throw поток выполнения останавливается, и следующая команда не выполнятся. Вместо этого начинается поиск подходящего для обработки сгенерированного исключения блока catch. Если такой блок не обнаруживается, используется обработчик по умолчанию.
Пример программы с явным выбрасыванием исключения приведен на слайде.
В классе ThrowDemo, помимо главного метода программы main(), описывается метод demoproc(), в котором явно выбрасывается исключение. Для начала создается объект исключения командой: NullPointerException ExObj = new NullPointerException("Ошибка!"). Точнее, это объект ExObj класса NullPointerException (ошибка операций с указателем). Используется конструктор класса NullPointerException с текстовым аргументом "Ошибка!". Этот текст впоследствии используется при выводе на экран описания возникшей ошибки.
Командой throw ExObj производится выбрасывание исключения. Поскольку все это происходит в блоке try, то начинается поиск подходящего блока catch для обработки исключения. В данном случае блок catch всего один, и это именно тот блок, который нужен. В этом блоке выводится сообщение о том, что исключение перехвачено в методе demoproc().
18

Генерирование исключений
Однако затем командой throw e снова выбрасывается исключение. Для того чтобы обработать это исключение, нужен внешний блок try с соответствующим блоком catch для обработки исключения. Поскольку в главном методе программы метод demoproc() вызывается в блоке try и для
исключения класса NullPointerException описан обработчик (выполняется команда System.out.println("Повторный перехват: "+e)), то выброшенное из метода demoproc() исключение перехватывается и обрабатывается.
Замечание 1. Вместо явного создания в методе demoproc() объекта исключения ExObj можно было ограничиться анонимным объектом, объединив команды создания объекта исключения и его выбрасывания в одну команду вида: throw new NullPointerException("Ошибка!"). Обычно так и поступают, поскольку это экономит место и время, а результат в принципе тот же.
Замечание 2. Сообщение программы Повторный перехват: java.lang.NullPointerException: Ошибка! возникает в результате обработки повторно выброшенного исключения вне метода demoproc(), в то время как объект исключения с текстовым параметром Ошибка! создавался в этом методе. Последовательность действий, которые приводят к такому результату, следующая. При выбрасывании исключения в методе demoproc() объект исключения (то есть объект ExObj) передается аргументом в блок catch. Аргумент в этом блоке обозначен как e, но это формальное название аргумента. Такие же формальные названия для аргументов используются при описании методов. Реально в блок передается объект ExObj. Далее в блоке catch есть команда throw e, кото- рая означает выброс исключения, переданного аргументом в блок catch. То есть это опять объект ExObj. Поскольку это второе исключение в методе demoproc() не обрабатывается, а передается во внешний блок try для перехвата и далее в соответствующий блок catch для обработки, то аргумент внешнего блока catch — это все тот же объект ExObj, который создавался конструктором с текстовым аргументом Ошибка!. Именно это описание ошибки и появляется на экране после передачи аргументом методу println() объекта исключения. Кроме этого описания автоматически отображается сообщение java.lang.NullPointerException:.
19

Выбрасывание исключений методами
Общий синтаксис метода, выбрасывающего исключения (которые не обрабатываются в методе):
тип_результата имя_метода(аргументы) throws исключение1,исключение2,...
{ // тело метода }
20