ITI0011RUS:Exceptions

Allikas: Kursused
Mine navigeerimisribale Mine otsikasti

Вернуться на страницу предмета

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

В своей работе программист должен предвидеть все возможные ошибки и нештатные ситуации, которые могут возникнуть в программе и запрограммировать соответствующие ответные действия программы при их возникновении. Язык Java позволяет обрабатывать ошибки во время их возникновения - такие непредвиденные ошибочные ситуации называются исключениями (exceptions).

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

Исключения в языке Java - это объекты, которые наследуются от класса Exception и образуют целую иерархию. Исключения далее делятся на типы (исключения форматирования, исключения обращения в памяти/индексирования, исключения операций ввода-вывода и т.д), а они в свою очередь делятся на конкретные исключения определенного типа, например, IndexOutOfBoundsException - исключение, которое возникает, когда код пытается прочитать ячейку массива с несуществующим индексом.

Когда в программе возникает исключения, говорят что определенный участок кода "выбрасывает исключение" (throws exception). Если исключение возникло - его где-то следует обработать. Необработанные исключения приводят к аварийному завершению работы программы, что является нежелательным эффектом с точки зрения пользователя и демонстрирует некомпенентность разработчика.

1. Обработка исключения в месте его возникновения

Для того, чтобы обработать исключение в том же месте в коде (в той же функции или методе) где оно возникло следует код, который потенциально способен выкинуть исключение, поместить внутрь блока try..catch. Параметром к инструкции catch выступает тип исключения, который мы хотим отловить. Также следует помнить о том, что блок try это блок кода, который имеет свою область видимости, поэтому внутрь этого блока также следует поместить код, который не выбрасывает исключений, но который предоставляет необходимые для работы переменные и объекты коду, который может выкинуть исключение:

<source lang="java"> try {

   int[5] a = {1,2,3,4,5};
   int z = a[-1];

} catch(IndexOutOfBoundsException e) {

   System.err.println("Invalid read operation");

} </source>

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

<source lang="java"> try {

   double determinant = M[0][0]*M[1][1] - 
           M[0][1]*M[1][0];
   System.out.println("The determinant of M is " + 
           determinant);

} catch ( ArrayIndexOutOfBoundsException e ) {

   System.out.println("M is the wrong size to have a determinant.");

} catch ( NullPointerException e ) {

   System.out.println("Programming error! M doesn't 
           exist. " + e.getMessage());

} </source>

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

ArrayIndexOutOfBoundsException возникает тогда, если массив M, c которым работает код имеет размерность меньше, чем 2х2. Поскольку код пытается прочесть вторые ячейки массива (под индексом 1), то в случае, если размер массива будет меньше, это приведет к исключению - попытке прочитать значение массива по несуществующему индексу.

NullPointerException возникнет в случае, если объекта M не существует. Например, если данная переменная была объявлена, но не проинициализирована.

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

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

<source lang="java"> try {

 /* Some code here */

} catch (IndexOutOfBoundsException e) {

 /* Some code here */

} catch (NullPointerException e) {

 /* Some code here */

} finally {

 /* Some code here */

} </source>

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

Например:

<source lang="java"> public static void main(String[] args) { foo(); }

public static void foo() { try { bar(null); } catch (IndexOutOfBoundsException e) { System.err.println("Invalid index"); } catch (NullPointerException e) { System.err.println("Invalid object specified."); } finally { System.err.println("Fatal error. Quitting."); System.exit(-1); } }

public static String bar(String parameter) throws IndexOutOfBoundsException, NullPointerException { if (parameter == null) throw new NullPointerException(); int[] a = {1,2,3,4,5}; int k = a[10]; /* throws IndexOutOfBoundsException */ return parameter.substring(0); }

</source>