
- •Лабораторна робота №5. Обробка виключень Хід роботи
- •Теоретичні відомості
- •Причини виникнення помилок
- •Обробка виняткових ситуацій
- •Використання оператора throw
- •Перевіряємі й неперевіряємі виключення
- •Створення користувальницьких класів виключень
- •Перевизначення методів і виключення
- •Особливі випадки
Використання оператора throw
Крім того, що визначена виняткова ситуація може бути порушена виконуючою системою Java, програміст сам може явно породити помилку. Робиться це за допомогою оператора throw.
Наприклад:
...
public int calculate(int theValue) {
if( theValue < 0) {
throw new Exception(
"Параметр для обчислення не повинен
бути відємним");
}
}
...
У цьому випадку передбачається, що як параметр методу може бути передане тільки додатне значення; якщо ця умова не виконана, то за допомогою оператора throw породжується виняткова ситуація. (Для успішної компіляції також потрібно в заголовку методу вказати throws Exception - це вираження розглядається нижче.)
Метод повинен делегувати обробку виняткової ситуації його коду, що викликав. Для цього в сигнатурі методу застосовується ключове слово throws, після якого повинні бути перераховані через кому всі виняткові ситуації, які може викликати даний метод. Тобто наведений вище приклад повинен бути наведений до наступного виду:
...
public int calculate(int theValue)
throws Exception {
if( theValue < 0) {
throw new Exception(
"Some descriptive info");
}
}
...
Таким чином, створення виняткової ситуації в програмі виконується за допомогою оператора throw з аргументом, значення якого може бути приведене до типу Throwable.
У деяких випадках після обробки виняткової ситуації може виникнути необхідність передати інформацію про неї в код, який викликаеться
У цьому випадку помилка з'являється вдруге.
Наприклад:
...
try {
...
} catch(IOException ex) {
...
// Обробка виняткової ситуації
...
// Повторне порушення виняткової
// ситуації
throw ex;
}
Розглянемо ще один випадок.
Припустимо, що оператор throw застосовується усередині конструкції try-catch.
try {
...
throw new IOException();
...
} catch(Exception e) {
...
}
У цьому випадку виключення, порушене в блоці try, не буде передано для обробки на більше високий рівень ієрархії, а обробиться в межах блоку try-catch, тому що тут міститься оператор, що може це виключення перехопити. Тобто відбудеться неявна передача керування на відповідний блок catch.
Перевіряємі й неперевіряємі виключення
Всі виняткові ситуації можна розділити на дві категорії: що перевіряються (checked) і непровіряютсья (unchecked).
Всі виключення, породжувані від Throwable, можна розбити на три групи. Вони визначаються трьома базовими типами: спадкоємцями Throwable - класами Error і Exception, а також спадкоємцем Exception - RuntimeException.
Помилки, породжені від Exception (і не є спадкоємцями RuntimeException), є що перевіряють. Т.е. під час компіляції перевіряється, чи передбачена обробка можливих виняткових ситуацій. Як правило, це помилки, пов'язані з оточенням програми (мережним, файловим вводом-виводом і ін.), які можуть виникнути поза залежністю від того, коректно написаний чи код ні. Наприклад, відкриття мережного з'єднання або файлу може привести до виникнення помилки й компілятор жадає від програміста передбачити якісь дії для обробки можливих проблем. У такий спосіб підвищується надійність програми, її стійкість при можливих збоях.
Виключення, породжені від RuntimeException, є неперевіряємі й компілятор не вимагає обов'язкової їхньої обробки.
Як правило, це помилки програми, які при правильному кодуванні виникати не повинні (наприклад, IndexOutOfBoundsException - вихід за межі масиву, java.lang.ArithmeticException - ділення на нуль). Тому, щоб не загромаджувати програму, компілятор залишає на розсуд програміста обробку таких виключень за допомогою блоків try-catch.
Виключення, породжені від Error, також не перевіряються. Вони призначені для того, щоб повідомити додаток про виникнення фатальної ситуації, що програмним способом усунути практично неможливо (хоча формально оброблювач допускається). Вони можуть свідчити про помилки програми, але, як правило, це непереборні проблеми на рівні JVM. Як приклад можна призвести до StackOverflowError (переповнення стека), OutOfMemoryError (недостача пам'яті).
Если в конструкції обробки виключень використається декілька операторів catch, класи виключень потрібно перераховувати в них послідовно, від менш загального до більше загального. Розглянемо два приклади:
try {
...
}
catch(Exception e) {
...
}
catch(IOException ioe) {
...
}
catch(UserException ue) {
...
}
Рис.
1.
Ієрархія класів стандартних виключень.
У даному прикладі при виникненні виняткової ситуації (клас, породжений від Exception) буде виконуватися завжди тільки перший блок catch. Інші не будуть виконані ні при яких умовах. Ця ситуація відслідковується компілятором, що повідомляє про UnreachableCodeException (помилка - недосяжний код). Правильно дана конструкція буде виглядати так:
try {
...
}
catch(UserException ue) {
...
}
catch(IOException ioe) {
...
}
catch(Exception e) {
...
}
У цьому випадку буде виконуватися послідовна обробка виключень. І у випадку, якщо не передбачена обробка того типу виключення, що виникло (наприклад, AnotherUserException), буде виконаний блок catch(Exception e){:}
Якщо спрацьовує один із блоків catch, то інші блоки в даній конструкції try-catch виконуватися не будуть.