Java тілінде алып тастауды үйрену

Алып тастауларды өңдеу
Исключение в Java — это объект, который описывает исключительное состояние, воз¬никшее в каком-либо участке программного кода. Когда возникает ис¬ключительное состояние, создается объект класса Exception. Этот объект пересылается в метод, обрабатывающий данный тип исключительной ситуации. Исключения могут возбуждаться и «вруч¬ную» для того, чтобы сообщить о некоторых нештатных ситуациях.

Основы
К механизму обработки исключений в Java имеют отношение 5 клю¬чевых слов: — try, catch, throw, throws и finally. Схема работы этого механизма следующая. Вы пытаетесь (try) выполнить блок кода, и если при этом возникает ошибка, система возбуждает (throw) исключение, ко¬торое в зависимости от его типа вы можете перехватить (catch) или пере¬дать умалчиваемому (finally) обработчику.
Ниже приведена общая форма блока обработки исключений.
try {
// блок кода }
catch (ТипИсключения1 е) {
// обработчик исключений типа ТипИсключения1 }
catch (ТипИсключения2 е) {
// обработчик исключений типа ТипИсключения2
throw(e) // повторное возбуждение исключения }
finally {
}

ЗАМЕЧАНИЕ
В языке Delphi вместо ключевого слова catch используется except.

Типы исключений
В вершине иерархии исключений стоит класс Throwable. Каждый из типов исключений является подклассом класса Throwable. Два непосредственных наследника класса Throwable делят иерархию подклассов исключений на две различные ветви. Один из них — класс Ехception — используется для описания исключительных ситуации, кото¬рые должны перехватываться программным кодом пользователя. Другая ветвь дерева подклассов Throwable — класс Error, который предназначен для описания исклю¬чительных ситуаций, которые при обычных условиях не должны перехватываться в пользовательской программе.

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

class Exc0 {
public static void main(string args[]) {
int d = 0;
int a = 42 / d;
} }

Вот вывод, полученный при запуске нашего примера.
С:\> java Exc0
java.lang.ArithmeticException: / by zero
at Exc0.main(Exc0.java:4)

Обратите внимание на тот факт что типом возбужденного исклю¬чения был не Exception и не Throwable. Это подкласс класса Exception, а именно: ArithmeticException, поясняющий, какая ошибка возникла при выполнении программы. Вот другая версия того же класса, в кото¬рой возникает та же исключительная ситуация, но на этот раз не в про¬граммном коде метода main.

class Exc1 {
static void subroutine() {
int d = 0;
int a = 10 / d;
}
public static void main(String args[]) {
Exc1.subroutine();
} }

Вывод этой программы показывает, как обработчик исключений ис¬полняющей системы Java выводит содержимое всего стека вызовов.
С:\> java Exc1
java.lang.ArithmeticException: / by zero
at Exc1.subroutine(Exc1.java:4)
at Exc1.main(Exc1.java:7)

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

class Exc2 {
public static void main(String args[]) {
try {
int d = 0;
int a = 42 / d;
}
catch (ArithmeticException e) {
System.out.println(«division by zero»);
}
} }

Целью большинства хорошо сконструированных catch-разделов долж¬на быть обработка возникшей исключительной ситуации и приведение переменных программы в некоторое разумное состояние — такое, чтобы программу можно было продолжить так, будто никакой ошибки и не было (в нашем примере выводится предупреждение – division by zero).

Несколько разделов catch
В некоторых случаях один и тот же блок программного кода может воз¬буждать исключения различных типов. Для того, чтобы обрабатывать по¬добные ситуации, Java позволяет использовать любое количество catch-разделов для try-блока. Наиболее специализированные классы исключений должны идти первыми, поскольку ни один подкласс не будет достигнут, если поставить его после суперкласса. Следующая про¬грамма перехватывает два различных типа исключений, причем за этими двумя специализированными обработчиками следует раздел catch общего назначения, перехватывающий все подклассы класса Throwable.

class MultiCatch {
public static void main(String args[]) {
try {
int a = args.length;
System.out.println(«a = » + a);
int b = 42 / a;
int c[] = { 1 };
c[42] = 99;
}
catch (ArithmeticException e) {
System.out.println(«div by 0: » + e);
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println(«array index oob: » + e);
}
} }

Этот пример, запущенный без параметров, вызывает возбуждение ис-ключительной ситуации деления на нуль. Если же мы зададим в командной строке один или несколько параметров, тем самым установив а в значение боль¬ше нуля, наш пример переживет оператор деления, но в следующем опе¬раторе будет возбуждено исключение выхода индекса за границы масси¬ва ArrayIndexOutOf Bounds. Ниже приведены результаты работы этой программы, за¬пущенной и тем и другим способом.
С:\> java MultiCatch
а = 0
div by 0: java.lang.ArithmeticException: / by zero
C:\> java MultiCatch 1
a = 1
array index oob: java.lang.ArrayIndexOutOfBoundsException: 42

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

class MultiNest {
static void procedure() {
try {
int c[] = { 1 };
c[42] = 99;
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println(«array index oob: » + e);
} }
public static void main(String args[]) {
try {
int a = args.length();
System.out.println(«a = » + a);
int b = 42 / a;
procedure();
}
catch (ArithmeticException e) {
System.out.println(«div by 0: » + e);
}
} }

throw
Оператор throw используется для возбуждения исключения «вруч¬ную». Для того, чтобы сделать это, нужно иметь объект подкласса клас¬са Throwable, который можно либо получить как параметр оператора catch, либо создать с помощью оператора new. Ниже приведена общая форма оператора throw.
throw ОбъектТипаThrowable;

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

class ThrowDemo {
static void demoproc() {
try {
throw new NullPointerException(«demo»);
}
catch (NullPointerException e) {
System.out.println(«caught inside demoproc»);
throw e;
} }
public static void main(String args[]) {
try {
demoproc();
}
catch(NulPointerException e) {
System.out.println(«recaught: » + e);
}
} }

В этом примере обработка исключения проводится в два приема. Метод main создает контекст для исключения и вызывает demoproc. Метод demoproc также устанавливает контекст для обработки исключе¬ния, создает новый объект класса NullPointerException и с помощью опе¬ратора throw возбуждает это исключение. Исключение перехватывается в следующей строке внутри метода demoproc, причем объект-исключение доступен коду обработчика через параметр e. Код обработчика выводит сообщение о том, что возбуждено исключение, а затем снова возбуждает его с помощью оператора throw, в результате чего оно передается обра¬ботчику исключений в методе main. Ниже приведен результат, получен¬ный при запуске этого примера.

С:\> java ThrowDemo
caught inside demoproc
recaught: java.lang.NullPointerException: demo

throws
Если метод способен возбуждать исключения, которые он сам не об¬рабатывает, он должен объявить о таком поведении, чтобы вызывающие методы могли защитить себя от этих исключений. Для задания списка исключений, которые могут возбуждаться методом, используется ключе¬вое слово throws. Если метод в явном виде (т.е. с помощью оператора throw) возбуждает исключе¬ние соответствующего класса, тип класса исключений должен быть ука¬зан в операторе throws в объявлении этого метода. С учетом этого наш прежний синтаксис определения метода должен быть расширен следую¬щим образом:

тип имя_метода(список аргументов) throws список_исключений {}

Ниже приведен пример программы, в которой метод procedure пыта¬ется возбудить исключение, не обеспечивая ни программного кода для его перехвата, ни объявления этого исключения в заголовке метода. Такой программный код не будет оттранслирован.

class ThrowsDemo1 {
static void procedure() {
System.out.println(«inside procedure»);
throw new IllegalAccessException(«demo»);
}
public static void main(String args[]) {
procedure();
} }

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

class ThrowsDemo {
static void procedure() throws IllegalAccessException {
System.out.println(» inside procedure»);
throw new IllegalAccessException(«demo»);
}
public static void main(String args[]) {
try {
procedure();
}
catch (IllegalAccessException e) {
System.out.println(«caught » + e);
}
} }

Ниже приведен результат выполнения этой программы.
С:\> java ThrowsDemo
inside procedure
caught java.lang.IllegalAccessException: demo

finally
Иногда требуется гарантировать, что определенный участок кода будет выпол¬няться независимо от того, какие исключения были возбуждены и пере¬хвачены. Для создания такого участка кода используется ключевое слово finally. Даже в тех случаях, когда в методе нет соответствующего воз¬бужденному исключению раздела catch, блок finally будет выполнен до того, как управление перейдет к операторам, следующим за разделом try. У каждого раздела try должен быть по крайней мере или один раз¬дел catch или блок finally. Блок finally очень удобен для закрытия файлов и освобождения любых других ресурсов, захваченных для времен¬ного использования в начале выполнения метода. Ниже приведен пример класса с двумя методами, завершение которых происходит по разным причинам, но в обоих перед выходом выполняется код раздела finally.

class FinallyDemo {
static void procA() {
try {
System.out.println(«inside procA»);
throw new RuntimeException(«demo»);
}
finally {
System.out.println(«procA’s finally»);
} }
static void procB() {
try {
System.out.println(«inside procB»);
return;
}
finally {
System.out.println(«procB’s finally»);
} }
public static void main(String args[]) {
try {
procA();
}
catch (Exception e) {}
procB();
} }

В этом примере в методе procA из-за возбуждения исключения про¬исходит преждевременный выход из блока try, но по пути «наружу» вы¬полняется раздел finally. Другой метод procB завершает работу выпол¬нением стоящего в try-блоке оператора return, но и при этом перед выходом из метода выполняется программный код блока finally. Ниже приведен результат, полученный при выполнении этой программы.

С:\> java FinallyDemo
inside procA
procA’s finally
inside procB
procB’s finally

Подклассы Exception
Только подклассы класса Throwable могут быть возбуждены или пере¬хвачены. Простые типы — int, char и т.п., а также классы, не являю¬щиеся подклассами Throwable, например, String и Object, использоваться в качестве исключений не могут. Наиболее общий путь для использова¬ния исключений — создание своих собственных подклассов класса Ex¬ception. Ниже приведена программа, в которой объявлен новый подкласс класса Exception.

class MyException extends Exception {
private int detail;
MyException(int a) {
detail = a:
}
public String toString() {
return «MyException[» + detail + «]»;
}
}
class ExceptionDemo {
static void compute(int a) throws MyException {
System.out.println(«called computer + a + «).»);
if (a > 10)
throw new MyException(a);
System.out.println(«normal exit.»);
}
public static void main(String args[]) {
try {
compute(1);
compute(20);
}
catch (MyException e) {
System.out.println(«caught» + e);
}
} }

Этот пример довольно сложен. В нем сделано объявление подкласса MyException класса Exception. У этого подкласса есть специальный кон¬структор, который записывает в переменную объекта целочисленное значение, и совмещенный метод toString, выводящий значение, хранящееся в объекте-исключении. Класс ExceptionDemo определяет метод compute, который возбуждает исключение типа MyExcepton. Простая логика метода compute возбуждает исключение в том случае, когда значение пара-ветра метода больше 10. Метод main в защищенном блоке вызывает метод compute сначала с допустимым значением, а затем — с недопус-тимым (больше 10), что позволяет продемонстрировать работу при обоих путях выполнения кода. Ниже приведен результат выполнения програм¬мы.

С:\> java ExceptionDemo
called compute(1).
normal exit.
called compute(20).
caught MyException[20]

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

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