Обработка исключительных ситуаций

Содержание

Слайд 2

Исключительные ситуации Общая схема использования блока try-catch-finally для обработки исключительных ситуаций:

Исключительные ситуации
Общая схема использования блока try-catch-finally для обработки исключительных ситуаций:
try{
//

код, который генерирует исключение
}
catch(Тип_исключения_1 объект){
// код для обработки исключения
}
catch(Тип_исключения_2 объект){
// код для обработки исключения
}
...
finally{
// код, который выполняется обязательно
}
Слайд 3

Исключительные ситуации Исключительная ситуация — это ошибка, которая возникает в результате

Исключительные ситуации

Исключительная ситуация — это ошибка, которая возникает в результате

выполнения программы. Исключение в Java — это объект, который описывает исключительную ситуацию (ошибку).
При возникновении исключительной ситуации в процессе выполнения программы автоматически создается объект, описывающий эту исключительную ситуацию . Этот объект передается для обработки методу, в котором возникла исключительная ситуация. Говорят, что исключение выбрасывается в метод. По получении объекта исключения метод может обработать его или передать для обработки дальше.
В Java для обработки исключительных ситуаций используется блок try-catch-finally. В блок try помещается программный код, который отслеживается на случай, если возникнет исключительная ситуация. Если исключительная ситуация возникает, то управление передается блоку catch. Программный код в этом блоке выполняется, только если возникает исключительная ситуация, причем не любая, а определенного типа. Аргумент, определяющий, какого типа исключительные ситуации обрабатываются в блоке catch, указывается после ключевого слова catch в круглых скобках, то есть в том же формате, что и аргумент метода.
Поскольку в блоке try могут возникать исключения разных типов, для каждого из них можно предусмотреть свой блок catch. Если блоков catch несколько, при возникновении исключительной ситуации они перебираются последовательно до совпадения типа исключительной ситуации с аргументом блока catch.
После блоков try и catch можно указать блок finally с кодом, который выполняется в любом случае вне зависимости от того, возникла исключительная ситуация или нет.
Слайд 4

Исключительные ситуации Может случиться, что в блоке try возникла ошибка, но

Исключительные ситуации

Может случиться, что в блоке try возникла ошибка, но

подходящего блока catch для ее обработки нет. В этом случае исключение выбрасывается из метода и должно быть обработано внешним к методу программным кодом. Согласно правилам языка Java, исключения, которые не обрабатываются в методе и выбрасываются из метода, указываются в сигнатуре метода после ключевого слова throws. То есть указываются классы выбрасываемых из метода исключений. Правда, далеко не все классы выбрасываемых исключений нужно указывать — только так называемые неконтролируемые исключения. Мы рассмотрим их позже.
Если возникает ошибка, обработка которой в программе не предусмотрена, используется обработчик исключительной ситуации по умолчанию. Самое трагическое последствие вызова обработчика по умолчанию состоит в том, что программа завершает работу.
Есть еще одно ключевое слово, которое достаточно часто используется при обработке исключительных ситуаций, а точнее, при генерировании исключительной ситуации. Это ключевое слово throw.
Слайд 5

Классы исключений Иерархия классов-исключений Error Object ? Throwable ? Exception ?

Классы исключений

Иерархия классов-исключений
Error
Object ? Throwable ?
Exception

?
RuntimeException
Пример 1. Обработка ошибки деления на ноль
Слайд 6

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

Классы исключений

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

исключительных ситуаций. В вершине этой иерархии находится суперклассThrowable. У этого суперкласса есть два подкласса: Exception и Error. К классу Error относятся «катастрофические» ошибки, которые невозможно обработать в программе, например переполнение стека памяти. У класса Exception есть подкласс RuntimeException. К классу RuntimeException относятся ошибки времени вы-полнения программы, которые перехватываются программами пользователя.
Исключения для класса RuntimeException определяются автоматически. К ним относятся, например, деление на ноль, выход за пределы массива (недопустимая индексация массива).
Ошибка деления на ноль относится к классу ArithmeticException, который является подклассом класса RuntimeException. Для отслеживания этой ошибки код, который ее вызывает, заключается в блок try, а для обработки ошибки после блока try размещается блок catch. Аргументом в блок catch передается объект e класса ArithmeticException (объект исключения). В данном случае при обработке ошибки напрямую объект исключения e не используется, но в принципе такая ситуация возможна и часто встречается.
При делении на ноль на экран выводится сообщение Деление на ноль!. Работа программы при этом не завершается и выводится сообщение Выполнение программы продолжено!.
Слайд 7

Классы исключений Пример 2. Обработка ошибки деления на ноль

Классы исключений
Пример 2. Обработка ошибки деления на ноль

Слайд 8

Классы исключений В главном методе создаются три целочисленные переменные a, b

Классы исключений

В главном методе создаются три целочисленные переменные a, b

и c с нулевыми начальными значениями. Командой Random r=new Random() создается объект r класса Random. Для генерирования целого числа служит метод nextInt(), который вызывается из объекта r. Аргументом метода указывается верхняя граница диапазона генерируемых чисел. Нижняя граница диапазона генерируемых чисел равна нулю.
Далее запускается цикл с достаточно большим количеством итераций. В рамках каждого цикла последовательно выполняются команды b=r.nextInt(200), c=r.nextInt(100) и a=10000/b/c. Поскольку переменные b и c получают случайные значения, в том числе это может быть ноль, то при выполнении команды a=10000/b/c возможно деление на ноль. Поэтому соответствующие команды заключены в блок try.
В блоке catch{}, предназначенном для обработки исключительной ситуации деления на ноль, выполняются команды System.out.println("Деление на ноль!") и a=0. В результате при попытке деления на ноль выводится соответствующее сообщение, а переменная a получает нулевое значение. Работа цикла при этом продолжается. В частности, значение переменной a выводится на экран. Фрагмент результат выполнения программы представлен на слайде.
Слайд 9

Описание исключительной ситуации Пример 3. Описание ошибки

Описание исключительной ситуации
Пример 3. Описание ошибки

Слайд 10

Описание исключительной ситуации В классе Throwable переопределяется метод toString(), который, как

Описание исключительной ситуации

В классе Throwable переопределяется метод toString(), который, как

известно, определен в общем суперклассе Object, причем переопределяется он так, что в качестве результата возвращает строку, описывающую соответствующую ошибку. Напомним, что метод toString() вызываетс автоматически, например, при передаче объекта исключения методу println() в качестве аргумента. Соответствующий пример представлен на слайде.
По сравнению с рассмотренным ранее особенность этого примера состоит в том, что в команде System.out.println("Ошибка: "+e) в качестве аргумента методу println() передается объект исключительной ситуации e.
Результат выполнения программы представлен на слайде.
В первой текстовой строке, выведенной на экран, текст после слова Ошибка: появился в результате преобразования объекта исключения e в текстовый формат.
Слайд 11

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

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

Слайд 12

Множественный блок catch{} Для каждого типа исключений можно предусмотреть свой блок

Множественный блок 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 содержит команду вывода разделительной «звездной линии», которая отображается независимо от того, произошла какая-либо ошибка или нет. Результат выполнения программы представлен на слайде.
Слайд 13

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

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

Слайд 14

Вложенные блоки try Один блок try может размещаться внутри другого блока

Вложенные блоки 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.
Слайд 15

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

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

Слайд 16

Вложенные блоки try Сразу отметим, что этот блок обрабатывает только исключение,

Вложенные блоки 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 представлен на слайде.
Слайд 17

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

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

Слайд 18

Генерирование исключений Для генерирования исключения используется ключевое слово throw. После инструкции

Генерирование исключений

Для генерирования исключения используется ключевое слово 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().
Слайд 19

Генерирование исключений Однако затем командой throw e снова выбрасывается исключение. Для

Генерирование исключений

Однако затем командой 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:.
Слайд 20

Выбрасывание исключений методами Общий синтаксис метода, выбрасывающего исключения (которые не обрабатываются

Выбрасывание исключений методами
Общий синтаксис метода, выбрасывающего исключения (которые не обрабатываются

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

Выбрасывание исключений методами Пример 7. Метод выбрасывает исключение

Выбрасывание исключений методами
Пример 7. Метод выбрасывает исключение

Слайд 22

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

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

Ранее отмечалось, что если метод выбрасывает или может

выбросить исключение, которое в методе не обрабатывается, этот факт нужно отразить при описании метода. В сигнатуре метода после ключевого слова throws перечисляются классы исключений, которые может выбрасывать метод. Причина такой предупредительности состоит в том, что внешним методам нужно сообщить, к каким неприятностям следует быть готовым при вызове данного метода. Ранее мы не использовали ключевое слово throws, хотя некоторые методы и выбрасывали исключения. Дело в том, что перечисляются далеко не все выбрасываемые методом исключения. В частности, не нужно явно указывать исключения класса Error, а также класса RuntimeException и его подклассов. Рассматривавшиеся ранее исключения как раз относились к подклассам RuntimeException.
Общий синтаксис описания метода, выбрасывающего исключения представлен на слайде.
Пример описания метода, выбрасывающего необрабатываемое исключение, приведен на слайде.
Программа достаточно простая и ее особенность лишь в том, что при описании метода throwOne() явно указано, что метод может выбрасывать исключение класса IllegalAccessException (ошибка доступа). Методом throwOne() выводится на экран сообщение об ошибке, затем выбрасывается исключение командой: throw new IllegalAccessException("Большая ошибка!").
В данном случае исключение — это анонимный объект класса IllegalAccessException, для создания которого использовался конструктор с текстовым аргументом. В методе это исключение не отслеживается и не обрабатывается, о чем и свидетельствует наличие в сигнатуре метода ключевого слова throws и названия класса исключения IllegalAccessException. Отметим, что если бы это исключение в методе обрабатывалось, необходимости указывать в сигнатуре метода ключевое слово throws (и класса исключения) не было бы.
В главном методе программы вызывается метод throwOne(), выбрасываемое методом исключение отслеживается и обрабатывается. Объект (анонимный) выброшенного методом исключения передается в блок catch.
Слайд 23

Контролируемые и неконтролируемые исключения Таблица1. Контролируемые исключения в Java :

Контролируемые и неконтролируемые исключения
Таблица1. Контролируемые исключения в Java :

Слайд 24

Контролируемые и неконтролируемые исключения Таблица2. Неконтролируемые исключения в Java :

Контролируемые и неконтролируемые исключения
Таблица2. Неконтролируемые исключения в Java :

Слайд 25

Контролируемые и неконтролируемые исключения Встроенные исключения в Java делятся на контролируемые

Контролируемые и неконтролируемые исключения

Встроенные исключения в Java делятся на контролируемые

и неконтролируемые. Фактически, перечислять выбрасываемые методом исключения в сигнатуре метода нужно только в том случае, если они неконтролируемые. В табл.1 приведены некоторые контролируемые исключения в Java.
Еще раз отметим, что даже если метод не обрабатывает и выбрасывает контролируемое исключение, отражать этот факт в сигнатуре метода не нужно. Неконтролируемые исключения указываются в сигнатуре метода, если они в этом методе не обрабатываются.
Слайд 26

Создание собственных исключений Таблица3. Методы класса Throwable :

Создание собственных исключений
Таблица3. Методы класса Throwable :

Слайд 27

Создание собственных исключений Классы встроенных исключений в Java описывают только наиболее

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

Классы встроенных исключений в Java описывают только наиболее

общие ошибки, поэтому в некоторых случаях нужно или полезно описать собственное исключение. В Java такая возможность имеется.
Технически создание собственного исключения сводится к созданию подкласса класса Exception, который, в свою очередь, является подклассом класса Throwable. В создаваемом подклассе ничего не нужно реализовывать. Что касается класса Exception, то он не определяет собственных методов, а наследует их из классаThrowable. Некоторые методы класса Throwable представлены в табл. 3.
Слайд 28

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

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

Слайд 29

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

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