ITI0011RUS:Exceptions
Вернуться на страницу предмета
Программист при написании кода должен принимать во внимание различные исключительные ситуации и сбои, которые могут возникнуть в работе создаваемой программы. Надежность работы программы - один из важных критериев, по которым оценивается программа. Чем надежней программа - тем с большим количеством нештатных ситуаций в работе она умеет справиться и продолжить свою работу.
В своей работе программист должен предвидеть все возможные ошибки и нештатные ситуации, которые могут возникнуть в программе и запрограммировать соответствующие ответные действия программы при их возникновении. Язык 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>