Top.Mail.Ru

Перечень уроков по Java

34. Исключения

Исключение (exception) — это ошибка, возникающая во время выполнения (runtime) программы. Исключения могут возникать во многих случаях, например: деление на нуль, нулевая ссылка, выход за границы массива,  попытка открыть несуществующий файл и другие. Но это не обязательно  ошибки программиста. Существуют  ситуации, предусмотреть которые невозможно, например, сбой оборудования.

Если возникает ошибка, обработка которой в программе не предусмотрена,  выполнение программы будет прервано в строке кода, содержащей ошибку. Такое аварийное завершение работы программы не очень хорошее решение. Рассмотрим,  какие решения предлагает Java.

 

Обработка исключений

Как и всё в Java, исключения тоже представлены в виде классов. Исключение в Java - это объект класса Exception, который содержит информацию об ошибке, включая тип ошибки и состояние программы, в котором произошла ошибка. Создание объекта-исключения и передача его на выполнение называется броском исключения (throw). Говорят, что исключение выбрасывается в метод. По получении объекта исключения метод может обработать его или передать для обработки дальше

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

try {

//здесь код, который может привести к ошибке

} catch(Имя класса исключения ex ){ //указывается класс исключения

//здесь код обработки исключения

}

finally{ // блок finally не обязателен

// выполняется в любом случае

}

В  заголовке блока catch, указывается имя класса исключения, для которого предназначен этот блок. Блок будет срабатывать только при возникновении данного исключения или исключения класса – наследника.

Имя ex в заголовке catch-блока — это произвольное имя. Оно служит для именования объекта-исключения и с его помощью можно извлечь информацию о возникшем исключении.

В Java используются следующие  ключевые слова для работы с исключениями:

  • try — начало блока кода, который может привести к ошибке
  • catch — начало блока кода обработки исключений
  • finally — начало блока кода, которой выполняется в любом случае
  • throw — служит для генерации исключений
  • throws — обозначает, что метод может выбросить исключение

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

public class MyException {

    public static void main(String[] args) {

            Scanner in = new Scanner(System.in);

            int n = in.nextInt();

            System.out.println("Результат 1/n= " + 1/n);

            System.out.println("Программа завершена");

            }

}

После запуска программы при вводе числа 0 на консоль будет выведено следующее сообщение:

0
Exception in thread "main" java.lang.ArithmeticException: / by zero
   at myexception.MyException.main(MyException.java:13)
в подпроцессе "main" произошло исключение класса ArithmeticException  деления на нуль: "/ by zero". Исключение возникло при выполнении метода main класса MyException.

Выполнение программы прервано на операторе System.out.println("Результат 1/n= " + 1/n); Последующая строка кода  System.out.println("Программа завершена"); не выполняется  и сообщение «Программа завершена» не выводится.

 

Выполним обработку исключительной ситуации – деление на нуль.  Для отслеживания  ошибки код, который ее вызывает, заключаем в блок try, а для обработки ошибки используем блок catch. Обработка ошибки – это просто вывод типа исключения.

public class MyException {

    public static void main(String[] args) {

        try{

            Scanner in = new Scanner(System.in);

            int n = in.nextInt();

            System.out.println("Результат 1/n= " + 1/n);

            } catch(Exception e) {

            System.out.println("Исключение:" +e); 

           }finally{

                System.out.println("Программа завершена");

           }  

    }

}

После запуска программы при вводе числа 0 на консоль будет выведено следующее сообщение:

0
Исключение:java.lang.ArithmeticException: / by zero
Программа завершена

 

При делении на ноль выводится  сообщение: «Исключение:java.lang.ArithmeticException: / by zero». Здесь важно то, что после попытки деления на ноль программа продолжает работу и выполняется блок  finally.

 

Для блока try-catch  может быть несколько блоков catch — каждый для своего исключения.

Пример.

Scanner in = new Scanner(System.in);

int n = in.nextInt();

try {

    inputFile("data.txt");

    System.out.println("Результат 1/n= " + 1/n);

} catch ( FileNotFoundException fe ) {

    System.out.println("Файл data.txt не найден");

} catch ( ArithmeticException e ) {

    System.out.println("Деление на ноль");

}

    

Если в блоке try возникнет одна из двух исключительных ситуаций — FileNotFoundException или ArithmeticException, то она будут перехвачена и сработает соответствующий блок catch. Если возникнет какое-то другое исключение, то оно не будет перехвачено  и работа программы будет аварийно завершена.

 

 

Классы исключительных ситуаций

 Теперь мы знаем, как обрабатывать исключения, но возникает вопрос, какие  исключения обрабатывать? Для ответа на него рассмотрим основные классы исключений

Throwable 
     |
     +------- Error
     |
     +------- Exceptoin
                  |
                  +------- RunTimeExceptoin
                                      |

 

Throwable — базовый класс для всех исключительных ситуаций.

Error — базовый класс для исключительных ситуаций, вызванных серьёзными сбоями в работе виртуальной машины Java, поэтому не следует пытаться обрабатывать такие исключительные ситуации  в собственной программе, поскольку на уровне программы их обработать невозможно. Например, устранить нехватку памяти или  переполнение стека.

Exception — это базовый класс для всех тех исключений, которые являются результатом проблем в программе, которые могут быть обработаны  и предсказуемы.

RuntimeException - это подкласс класса Exception. Он занимает особое место. К этому классу относятся ошибки времени выполнения программы – это ошибки программиста. Например, произошло деление на ноль, выход за границы массива,  попытка открыть несуществующий файл. Эти ошибки необходимо предусмотреть и устранить без привлечения исключений.  Использовать исключения следует только в крайних ситуациях. Следует помнить, что перехват и обработка исключений требует больших затрат и снижает быстродействие программы, поэтому злоупотреблять ими не следует.  

Транслятор автоматически обрабатывает ошибки класса RuntimeException, поэтому в программе обрабатывать эти ошибки не нужно.

Классы Error и RuntimeException образуют группу непроверяемых исключительных ситуаций – программисту их проверять не нужно.

Вот перечень основных непроверяемых исключений класса RuntimeException

 

Класс исключения

Описание

ArithmeticException

Арифметическая ошибка (например, деление на ноль)

ArrayIndexOutOfBoundsException

Индекс массива за пределами допустимых границ

ArrayStoreException

Присваивание элементу массива недопустимого значения

ClassCastException

Недопустимое приведение типов

IllegalArgumentException

Методу передан недопустимый аргумент

IndexOutOfBoundsException

Некоторый индекс находится за пределами  допустимых для него границ

NegativeArraySizeException

Создание массива отрицательного размера

NullPointerException

Недопустимое использование нулевого указателя

NumberFormatException

Недопустимое преобразование текстовой строки в числовой формат

StringIndexOutOfBoundsException

Попытка индексирования вне пределов строки

UnsupportedOperationException

Недопустимая операция

 

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

 Перечень основыных проверяемых исключений:

·   CloneNotSupportedException: класс, для объекта которого вызывается клонирование, не реализует интерфейс Clonable
·   InterruptedException: поток прерван другим потоком
  ClassNotFoundException: невозможно найти класс

 

Поскольку все классы исключений наследуются от класса Exception, то все они наследуют ряд его методов, которые позволяют получить информацию о характере исключения. Среди этих методов отметим наиболее важные:

 

Метод

Описание

fillInStackTrace()

возвращает объект Throwable, который содержит полную трассировку стека

getLocalizesMessage()

возвращает строку с локализованным описанием исключения

getMessage()

возвращает строку  с описанием исключения

printStackTrace()

возвращает массив, содержащий трассировку стека исключения

toString()

возвращает объект класса String, содержащий описание исключения

 

 

Оператор throw

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

Пример.

С помощью  оператора throw  создаем (бросаем) исключение  и затем перехватываем в блоке catch. В программе происходит ввод числа, и если число равно 0, то возникает исключение:

public static void main(String[] args) {

        try{

            Scanner in = new Scanner(System.in);

            int n = in.nextInt();

            if(n == 0){

               throw new Exception("Число n равно нулю");

              }

        }

        catch(Exception ex){

 System.out.println(ex.getMessage());

        }  finally{

                System.out.println("Программа завершена");

           }  

    }

 

Будет выведено
0
Число n равно нулю
Программа завершена

  

Оператор throws

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

Пример.

    // Описание метода:

    static void  method(int n) throws Exception{

          // Выбрасывание исключения:

    if(n == 0){

              throw new Exception("Ошибка в методе  method. Число n равно нулю");

              }

         System.out.println("Работает method!");

      }  

   

    public static void main(String[] args) {

       

        try{

            method(0);

         // Метод выбрасывает исключение

        }catch(Exception e){

            // Обработка исключения

            System.out.println("Обработка исключения: "+e);

        }

 

Будет выведено:
Обработка исключения: java.lang.Exception:  Ошибка в методе  method. Число n равно нулю