Лабораторная работа 3 наследование. Обработка исключительных ситуаций
Скачать 174.69 Kb.
|
ЛАБОРАТОРНАЯ РАБОТА № 3 НАСЛЕДОВАНИЕ.ОБРАБОТКА ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ Цель работы – знакомство с иерархией классов исключений и получение навыков обработки ошибок. КРАТКАЯ ТЕОРИЯ НаследованиеДля того чтобы разобраться в работе классов объектов Java, в том числе и исключений, следует коснуться фундаментального прин- ципа объектно-ориентированного программирования – наследова- ния – и пояснить что это такое. Прежде всего, необходимо отметить, что все классы Java явля- ются наследниками каких-то других классов, как показано в иерархии классов на рис. 3.1. class G class B class F class P class C Стрелкауказывает,что классСрасширяет (extends)классB Рис.3.1 содержимое класса Наследование одного класса от другого можно записать так: class C extends B{… // класс B– родитель,классС –потомок } Класс-потомок (дочерний класс) наследует все методы класса- предка (родительского класса), а также расширяет (extends) роди- тельский класс, добавляя ему новые методы и, соответственно, уве- личивая его функциональность. На вершине иерархии классов находится класс Object. Он явно или косвенно наследуется всеми классами. Если в сигнатуре (заголовке) ка- кого-либо класса не указан другой класс, от которого он порожден, то по умолчанию считается, что он является наследником непосредствен- но класса Object. Все классы, которые рассматривались в предыдущих лабораторных работах, были наследниками класса Object. Каждый класс-потомок может иметь только один класс-предок. Так как всем классам-наследникам доступны методы их родите- лей, методы класса Object доступны всем другим классам. В качестве справки в табл. 3.1 приведены некоторые из методов класса Object, которые можно использовать в любой программе. Таблица3.1
Иерархия исключенийИсключение – это ошибка, возникающая во время исполнения программы (но не в процессе компиляции). В JVM (java-машине) предусмотрена реакция на любую ошибку – автоматическое срабаты- вание обработчика исключений по умолчанию. В результате этого программа завершает свою работу, а пользователь видит на экране сформированную трассу стека (Stack Trace), где указывается класс, соответствующий перехваченному исключению, место расположения ошибки и последовательность вызываемых методов, через которые эта ошибка передается («летит»). На рис. 3.2 показано, что при ис- пользовании чисел, сгенерированных случайным образом, возможно возникновение ситуации деления на ноль (/ by zero). Трасса стека (Stack Trace) читается снизу вверх следующим образом: метод main вызвал метод m1(), который вызвал метод m2(), где произошла ис- ключительная ситуация Exception (ошибка) – деление на ноль /by zero, в резуль- тате чего был создан и перехвачен экземпляр класса исключений ArithmeticException пакета java.lang Рис.3.2 Чтобы разбираться в исключительных ситуациях и уметь кор- ректно реагировать на них в программе, следует ознакомиться с иерархией наследования классов исключений. На рис. 3.3 представ- лены четыре базовых класса исключений: Throwable, Error, Excep- tion, RuntimeException – от них наследуются все остальные классы исключений Java. где ch – checked; un – unchecked Рис.3.3 На вершине иерархии исключений стоит класс Throwable, явля- ющийся наследником класса Object. Каждый из типов исключений является подклассом класса Throwable. Два непосредственных наследника класса Throwable – Error и Exception делят иерархию подклассов исключений на две различные ветви. Каждый из базовых классов исключений имеет определенный статус, который нельзя изменять – это checked/unchecked (проверяе- мый/непроверяемый). Все остальные наследники классов исключений имеют такой же статус, как и базовый класс, от которого они порождены. Если исключение checked (Throwable, Exception или их потом- ки), то при написании программы компилятор будет выдавать ошиб- ку (подчеркивать красной волнистой линией) и требовать от разра- ботчика программного обеспечения самостоятельно (вручную) пере- хватить и обработать ошибку. Если исключение unchecked (Error, RuntimeException или их потомки), то компилятор не проверяет, может ли быть порождена ошибка в коде, и разработчик сам принимает решение, как поступать в данной ситуации. В случае, представленном на рис. 3.2, возникала unchecked ошибка, которая в программе не перехватывалась. Следует отметить, что обработка исключительных ситуаций класса IOException и его наследников, обеспечивающих безопасность работы с файлами, является одним из важных достоинств языка. На рис. 3.4 изображено более полное дерево классов исключений, где показаны наиболее часто используемые классы стандартных ошибок Java, и с которыми придется сталкиваться при выполнении лабораторных работ. ClassCastException (неприводимые типы) NullPointerException (вызов метода для переменной ссылочного типа с Null-значением) ArithmeticException (арифметические ошибки, например деление на 0 и др.) NumberFormatException (неверный формат числа) Рис.3.4 Обработка исключенийДля работы с экземплярами классов исключений используются пять ключевых слов: try – попытаться выполнить; catch – перехва- тить и обработать ошибку; finally – окончательно (финальный блок, выполняемый всегда); throw – генерация («бросание») исключения; throws – пометка метода, «бросающего» исключение. Ниже приведена общая форма записи обработки исключений. try {// блоккода,вызывающегоошибку }catch (ТипИсключения1 е) { // обработчикисключенийтипаТипИсключения1 } catch (ТипИсключения2 е) { // обработчикисключенийтипаТипИсключения2 throw(e) // возможноповторноевозбуждениеисключения } finally {} Возможны следующие варианты использования блоков: try-catch (или try-catch-catch-catch…); try-catch-finally (возможно: try-catch-catch-catch-…-finally); try-finally. Сгенерировать необходимую ошибку можно, используя следую- щий синтаксис: throw new Тип_исключения(); Тип исключения соответствует классу иерархии исключений стандартной библиотеки Java или созданного разработчиком и уна- следованного от стандартного класса. Несмотря на то, что самостоятельно создавать наследников, «бросать» исключения и перехватывать можно для любого класса иерархии, не рекомендуется это делать для классов Throwable и Er- ror. Автоматически экземпляры класса Throwable не создаются и не перехватываются. Обработка исключений класса Error и его наслед- ников возлагается на JVM. Разработчику рекомендуется работать с checked исключениями класса Exception и его наследниками и с unchecked исключениями класса RuntimeException и его наследниками. Далее рассмотрим примеры обработки исключительных ситуаций. Пример 3.1. Сгенерировано и перехвачено RuntimeException. public static void main(String[] args) { try { System.out.println("0"); throw new RuntimeException("Непроверяемая ошибка"); «брошено»исключение созданэкземплярRuntimeExceptionссообщением } catch (RuntimeException e) { // исключениеперехвачено System.out.println("1 "+ e); // исключениеобработано } System.out.println("2"); } Предок может перехватывать исключения всех своих потомков. Пример 3.2. Исключение перехвачено перехватчиком предка. public static void main(String[] args) { try { System.out.println("0"); throw new RuntimeException("Непроверяемая ошибка"); System.out.println("1"); } catch (Exception e) { System.out.println("2 "+ e ); } System.out.println("3"); } Пример 3.3. Перехват исключения подходящим классом. public static void main(String[] args) { try { System.out.println("0"); throw new RuntimeException("ошибка"); } catch (NullPointerException e) { System.out.println("1" ); }catch (RuntimeException e) { System.out.println("2" ); }catch (Exception e) { System.out.println("3" ); } System.out.println("4"); } Пример 3.3. Перехват исключения подходящим классом. public static void main(String[] args) { try { System.out.println("0"); throw new RuntimeException("ошибка"); } catch (NullPointerException e) { System.out.println("1" ); }catch (Exception e) { System.out.println("2" ); }catch (Error e) { System.out.println("3" ); } System.out.println("4"); } Пример 3.5. Исключение не перехвачено. public static void main(String[] args) { try { System.out.println("0"); throw new RuntimeException("ошибка"); } catch (NullPointerException e) { System.out.println("1" ); } System.out.println("2"); } Пример 3.6. Последовательность перехвата должна соответство- вать иерархии классов исключений. Предок не должен перехватывать исключения раньше потомков. Указанный пример выдает ошибку компилятора. Программу запустить невозможно. public static void main(String[] args) { try { System.out.println("0"); throw new NullPointerException("ошибка"); } catch (ArithmeticException e) { System.out.println("1" ); }catch (Exception e) { System.out.println("2" ); } catch (RuntimeException e) { System.out.println("3" ); поменять местами об-работчики } System.out.println("4"); } Пример 3.7. Нельзя перехватить брошенное исключение с помо- щью чужого catch, даже если перехватчик подходит. public static void main(String[] args) { try { System.out.println("0"); throw new NullPointerException("ошибка"); } catch (NullPointerException e) { } System.out.println("1" ); throw new ArithmeticException(); }catch (ArithmeticException e) { System.out.println("2" ); } System.out.println("3"); дляперехватаданногоисклю-чениянеобходимосоздатьно-вый обработчик Далее приведены примеры с использованием конструкции try- finally. Перехват брошенного исключения catch не производится. Секция finally выполняется всегда. Пример 3.8. Генерация исключения в методе. public class Except1{ public static int m(){ try { System.out.println("0"); throw new RuntimeException(); } finally { System.out.println("1"); } } public static void main(String[] args) { System.out.println(m()); }} Пример 3.9. Генерация исключительной ситуации в методе и до- полнительное использование оператора return. public class Except2 { public static int m(){ try { System.out.println("0"); return 55; // выходизметода } finally { System.out.println("1"); } } public static void main(String[] args) { System.out.println(m()); }} Пример 3.10. Генерация исключительной ситуации в методе. Ис- пользование оператора return в секциях try и finally. public class Except3 { public static int m(){ try { System.out.println("0"); return 15; } finally { System.out.println("1"); return 20; } } public static void main(String[] args) { System.out.println(m()); }} Пример 3.11.public class Except4 { public static void main(String[] args) { try { System.out.println("0"); throw new NullPointerException("ошибка"); } catch (NullPointerException e) { System.out.println("1" ); }finally { System.out.println("2" ); } System.out.println("3"); }} Пример 3.12. Исключение IllegalArgumentException – неверные аргументы. public class Except5 { public static void m(String str, double chislo){ if (str==null) { throw new IllegalArgumentException("Строка введена неверно"); } if (chislo>0.001) { throw new IllegalArgumentException("Неверное число"); } } public static void main(String[] args) { m(null,0.000001); }} Пример 3.13. Пример работы с аргументами метода main. На рис. 3.5 представлена настройка проекта и задание входных значений аргументов. public class Except6 { public static void main(String[] args) { try { int l = args.length; System.out.println("размер массива= " + l); int h=10/l; args[l + 1] = "10"; } catch (ArithmeticException e) { System.out.println("Деление на ноль"); }catch (ArrayIndexOutOfBoundsException e) { System.out.println("Индекс не существует"); } } } Рис.3.5 Через контекстное меню нужного проекта открыть диалоговое окно Свойства и установить нужные параметры аргументов метода main. Оператор ThrowsЕсли метод способен к порождению исключений, которые он не обрабатывает, он должен быть определен так, чтобы вызывающие методы могли сами предохранять от данного исключения. Для этого используется ключевое слово throws в сигнатуре метода. Это необходимо для всех исключений, кроме исключений типа Error и RuntimeException, и, соответственно, для любых их под- классов. Пример 3.13. Обработка исключения, порожденного одним ме- тодом m() в другом (в методе main). public class Except7 { public static void m(int x) throws ArithmeticException{ int h=10/x; } public static void main(String[] args) { try { int l = args.length; System.out.println("размер массива= " + l); m(l); } catch (ArithmeticException e) { System.out.println("Ошибка: Деление на ноль"); } } } Дополнительные примеры рекомендуется проработать, восполь- зовавшись источником [4]. ЗАДАНИЕ Для программы согласно заданному варианту (табл. 3.2): определить экспериментально, ошибки каких классов будут сгенерированы; создать обработчики исключительных ситуаций с использова- нием выявленных классов и всех секций конструкции обработчика с соответствующими сообщениями, позволяющими корректно выпол- нить программу. Задание выполнить в виде двух проектов: без использования соб- ственных методов и с использованием методов для каждой подзада- чи, которые могут генерировать исключительную ситуацию. Таблица3.2
СОДЕРЖАНИЕ ОТЧЕТА Отчет должен содержать следующие разделы: титульный лист; задание; словесное описание алгоритма; текст программы. |