Учим Java. Исключения

Учим Java. Исключения В предыдущей статье мы столкнулись с понятием исключения. Пришло время разобраться, что это такое и зачем это надо. Долгое время, еще до появления C++ и Java, у программистов существовал определенный алгоритм предварительной ловли исключительных ситуаций. Вследствие того, что код выходил внушительных объемов, обработку исключительных ситуаций делали только в крайних случаях. То ли дело сегодня.

Исключительные ситуации в C, будь то деление на ноль, ошибка записи в файл или какая-нибудь другая, в основном вылавливались с помощью кодов возврата функций. Т.е. в случае успешного выполнения функция возвращает одно значение, в случае ошибки функция возвращает код ошибки. В результате было бы просто расточительно проверять код возврата у каждой функции. Код программы был бы слишком объемным. Поэтому программисты проверяли код возврата только тех функций, в которых, по их мнению, могла бы возникнуть ошибка. К сожалению, не всегда это заканчивалось удачно: постоянно всплывали все новые исключения, вследствие чего приходилось изменять код программы, добавляя еще одно условие.
Сегодня средства обработки исключений в Java позволяют при минимальном объеме писать эффективный код, который будет работать практически в любых ситуациях. Помимо обработки исключений, Java предоставляет возможность создавать собственные классы исключений, что дает огромный потенциал при написании собственных классов.
Исключение — это проблемная ситуация, возникающая по мере выполнения кода программы. Исключения возникают во время выполнения программы (runtime), а не на этапе компиляции. В качестве примеров можно привести ошибки доступа к файлам, деление на ноль, открытия сокета и пр.
Существует два метода обработки исключений. Первый — это поймать исключение, выполнить какие-нибудь действия (например, вывести сообщение об ошибке) и завершить программу. Второй метод заключается в том, что после того, как было поймано исключение, осуществляется попытка повторного выполнения метода (или того, что вызвало исключение). Первый метод используется чаще, а вот второй значительно реже и не всегда может быть эффективным решением.
Знакомство с реализацией исключений в Java, пожалуй, начнем с приема ловли этих самых исключений. Для этого существует специальная конструкция try {} catch {}:
try
{
// код, который выбрасывает исключение
}
catch (Exception e)
{
// код, который выполняется при поимке исключения
}
В блоке try должны располагаться операторы, подозрительные на выброс исключения. Причем они могут быть разнотипными, и исключения, выбрасываемые ими, тоже могут быть разнотипными. Поэтому для того, чтобы поймать и обработать исключения двух разных типов, предусмотрено несколько блоков catch. Catch() — это по природе функция, которой передается параметр-экземпляр класса, унаследованного от базового класса Exception. В теле этой функции заключается обработчик исключения заданного типа. Обычно это вывод сообщения об ошибке.
Каждая функция catch, состоящая в конструкции для вылавливания исключений, обрабатывает только свой тип исключений. Этот тип задается в качестве параметра, о котором уже было сказано выше. Например:
try
{
// Код подозримый на исключительную ситуацию
}
catch (IOException e)
{
// Если исключение типа IOException, то выполняем этот код
}
catch (Exception e)
{
// Иначе, выполняем этот код
}
При возникновении исключения поиск подходящего блока catch идет последовательно вниз. Если тип выброшенного исключения совпадает с типом переданного параметра в catch, то выполняется именно этот блок. Если вы в качестве параметра для catch указали объект суперкласса для всех классов исключений Exception, то выполнится именно этот код. Это вполне логично. Каждый класс потомок унаследует все свойства и методы класса родителя. Передача в качестве параметра объекта суперкласса Exception обозначает безусловную обработку любого исключения. Это сильно напоминает ключевое слово default в конструкции switch. Именно таким образом и поступают, когда не известен тип исключения, но нужно его обработать в любом случае.
Иногда возникают ситуации, когда необходимо выполнить какие-либо действия независимо от того, были пойманы исключения в блоке try или нет. Специально для такого случая был предусмотрен дополнительный блок finally. Он описывается в конце всей структуры обработки исключений:
try
{
// ...
}
catch (Exception e)
{
// ...
}
finally
{
// Выполнить в любом случае
}
Приведу маленький пример, в котором можно выловить исключения, возникающие при открытии файла и чтении из него:
try
{
InputFile if = InputFile("test.file");
String s = if.getLine();
if.close();
}
catch (Exception e)
{
System.out.println("Что-то не так! ",e.getMessage());
}
У каждого экземпляра класса Exception и производных от него существуют базовые методы, с помощью которых мы можем получить подробную информацию о том, почему было брошено исключение. Перечислим некоторые из них:
toString() — возвращает короткое сообщение от базового класса
printStackTrace() — печатает полную трассировку базового класса
getMessage() — получает сообщение
На этом краткое знакомство с обработкой исключений можно завершить и перейти к теме создания собственных исключений.
Возможность создавать собственные исключения позволяет разработчикам библиотек, наборов классов и программ непосредственно предоставить программисту, который будет работать с данными библиотеками классов, уже готовый и сформированный полный интерфейс для работы с этой библиотекой.
Выбросить исключение может любой метод, причем выбрасывать исключение можно из любого места метода. Выброс сообщения происходит при помощи ключевого слова throw (от английского "бросать").
class MyException1 extends Exception {}
Этой строчкой мы создали новый класс MyException1, который унаследовал свойства и методы класса Exception. Другими словами, мы создали свое собственное исключение, которое, в принципе, ничем не отличается от суперкласса Exception.
Далее опишем в теле своей программы метод основного класса программы, например MyTrowing:
public void MyThrowing() throws MyException1
{
throw new MyException1();
}
В теле этого метода всего одна строчка, которая создает новый экземпляр нашего исключения и "выбрасывает" его. Ключевым словом throws мы указываем, исключения каких классов может выбросить этот метод. Это в большей степени нужно программисту, который будет смотреть исходных код, чтобы знать, чего ожидать от этого метода.
После этого можно попытаться словить наше исключение. Сделаем это в методе main() основного класса программы:
public static void main(String argv[])
{
try
{
MyThrowing();
}
catch (MyException1 e)
{
System.out.println("Мы словили его!;)");
}
}
При выполнении блока try метод MyThrowing() выбрасывает исключение, которое обрабатывается методом catch. В результате мы получаем выведенную строку, которая сообщает о том, что произошла исключительная ситуация. На этом можно закончить знакомство с исключениями в Java. С вопросами и предложениями — пишите.

Алексей Литвинюк


Компьютерная газета. Статья была опубликована в номере 14 за 2002 год в рубрике программирование :: java

©1997-2024 Компьютерная газета