Освоюємо Java/Винятки

Матеріал з Вікіпідручника
Перейти до: навігація, пошук

Виняткова ситуація або просто виняток (англ. exception) – це аварійний стан, який відбувається в кодовій послідовності під час виконання програми. Прикладом є — ділення на нуль, помилки читання з файла та мережі тощо. Іншими словами – це помилки які можуть виникнути при виконанні програми. В ряді мов програмування необхідно заздалегідь передбачити можливість тієї чи іншої помилки і передбачити шлях її обробки. В java для цього передбачений спеціальний механізм винятків.

Винятки в java[ред.]

Виняток в java – це об'єкт, який описує виняткову (тобто, помилкову) ситуацію, що відбулась в певному місці коду. Коли така ситуація виникає створюється об’єкт, який передається («вкидається») в метод, в якому виникла помилка. Далі в методі даний виняток може оброблятися, або бути переданий ще кудись для обробки.

Розглянемо для прикладу наступну програму

public class DivZero {
    public static void main(String args[]){
        int my=0;
        int medium=44/my;
        System.out.println("medium="+medium);
    }
}

Як бачимо в програмі присутнє ділення на нуль. При компіляції ми не отримаємо помилок. Проте, після запуску програми, отримаємо наступне:

Exception in thread "main" java.lang.ArithmeticException: / by zero
        at DivZero.main(DivZero.java:11)
Java Result: 1

Це так звана траса стеку викликів. Перший рядок означає тип-винятку. Як бачимо тут маємо ArithmeticException з діленням на нуль. java.lang – це пакет класів, який завжди доступний в програмі і який містить найбільш використовувані класи. Тобто його не потрібно імпортувати. Другий рядок вказує де саме відбулась виняткова ситуація: 11-й рядок у файлі DivZero.java в методі main() класу DivZero. При цьому як бачимо програма завершила своє виконання аварійно. Для уникнення цього існує відповідний механізм обробки винятків, який дозволяє перехопити виняток, одержати інформацію про нього, обробити його здійснивши певні дії для нормального закінчення або продовження виконання програми.

Типи винятків[ред.]

Усі типи винятків є підкласами класу Throwable, який входить в базовий пакет класів Java - java.lang. Тобто він є вершиною ієрархії класів винятків. Його два підкласи Error та Exception утворюють дві основні гілки винятків.

Клас Error з його підкласами - це помилки виконавчого середовища java. І які зазвичай не виникають при нормальній роботі середовища java. Такі винятки зазвичай не можуть бути оброблені в програмі.

Гілка класу Exception - це винятки, які програма повинна вловлювати(catch). Від даного класу та його підкласів можна утворювати власні підкласи. Важливим його підкласом є клас RuntimeException. Винятки даного типу включають такі винятки як ділення на нуль та помилкова індексація масивів.

Актуальну ієрархію класів винятків можна подивитися і уточнити в офіційній документації до JDK[1].

Конструкція try[ред.]

Для обробки виняткових ситуацій використовується п’ять ключових слів: try, catch, throw, throws та finally. Інструкції програми, в яких може виникнути помилка, контролюються за допомогою конструкції try.

Загальна форма наступна:

try{
//блок коду для контролю над помилками
} catch (тип-винятку1 об’єкт-винятку) {
   //дії при виникненні типу винятку1 (обробник винятку)
} catch (тип-винятку2 об’єкт-винятку) {
   //дії при виникненні типу винятку2 (обробник винятку)
}
 //….
[finally{
        //дії при виході з конструкції try.
 }]

Після інструкції try ми розміщуємо «небезпечний» код, у блоці catch відбувається обробка винятку, причому може бути кілька інструкцій catch. Завершувати конструкцію може інструкція finally, в ній розміщується код, який буде виконаний після обробки винятку в інструкції catch.

Таким чином можемо переписати програму з діленням на нуль:

public class DivZero {
    public static void main(String args[]){
        int my=0;
        try{
        int medium=44/my;
        System.out.println("medium="+medium);
        }catch(ArithmeticException e){
            System.out.println("Ділення на нуль!");
        }
        System.out.println("Продовження виконання...");
    }
}

Результат виконання:

Ділення на нуль!
Продовження виконання...

Як бачимо, для перехоплення винятку, код, через який виникала помилка, знаходиться у середині конструкції try. Також, зверніть увагу, що після виникнення виняткової ситуації наступний рядок System.out.println("medium="+medium); не було виведено, оскільки виняток був переданий для обробки в catch. Після інструкції програми в якій відбулась виняткова ситуація, всі наступні рядки до інструкції catch пропускаються і не будуть виконуватись. І, як бачимо з результату виконання, наша програма продовжила виконання по закінченню блоку try, а не завершила своє виконання аварійно.

try з ресурсами[ред.]

При використанні всередині try певних ресурсів, наприклад, файлів, при виникненні винятку необхідно було передбачити закриття відкритих ресурсів. Для цієї мети раніше приходилося використовувати блок finally. У Java 7 з'явилася конструкція try з ресурсами (англ. try-with-resources)[2]. Тепер просто можна створити ресурс у дужках зразу ж після ключового слова try і java сама потурбується про закриття ресурсу. Приклад:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

Throw[ред.]

В наведених вище прикладах ми здійснювали лише обробку винятків викинутих виконавчим середовищем java. Проте існує можливість викидання власних винятків. Для цього існує інструкція Throw. Загальна форма її наступна:

throw ThrowableInstance;

Тут ThrowableInstance – це тип винятку, який повинен бути або типом Throwable, або мати тип його підкласів. Щоб програма викинула ваш виняток необхідно скористатися оператором new. Для того, щоб одержати(перехопити) тип винятку можна скористатися інструкцією catch, як це ми робили вище.

Після інструкції throw відбувається аналогічне породження винятку як у вище наведених прикладах. Тобто усі інструкції пропускаються до найближчого блоку інструкції catch, де необхідно здійснити обробку винятку. Якщо catch не буде знайдено, то обробник винятків, що використовується по замовчуванню, призупиняє виконання програми і друкує відбиток стеку (stack trace).

Приклад:

public class ThrowNullException {
    public static void main(String args[]){
        try{
            throw new NullPointerException("Пробний виняток");
        }catch(Exception e){
            System.out.println("Наш витяток: "+e);
        }           
    }
}

Результат:

Наш витяток: java.lang.NullPointerException: Пробний виняток

Програма демонструє як створювати один із стандартних винятків. Більшість вбудованих run-time винятків Java мають щонайменше два конструктори. Один за замовчуванням без параметрів і один із параметром String, який дозволяє задати додатковий опис. Опис можна вивести на консоль за допомогою методів print(), println(). Також його можна отримати використавши метод getMessage() класу Throwable.

Можна створити власний тип винятку як підклас уже існуючого типу.

Throws[ред.]

Якщо метод породжує виняток і не обробляє його, то він повинен вказати про це, щоб обробка винятку була здійснена у місці виклику даного методу. Це здійснюється за допомогою застереження throws в оголошенні методу. Після нього вказується підряд через кому усі винятки, які можуть бути викинуті методом, окрім винятків класів Error та RuntimeException і їхніх підкласів. Нагадаємо, що клас Error – це необроблювані винятки, RuntimeException – винятки, які виникають в результаті помилки програміста (вихід за межі масиву, нульове посилання, невірне перетворення типів). Інші винятки – це помилки доступу, які доволі часто вимагають відповідної обробки.

Загальна форма оголошення методу наступна:

тип ім’я_методу(список_параметрів) throws список_винятків
{
// тіло методу
}

Наступна програма демонструє використання throws у методі де виникає виняток IllegalAccessException.

public class ThrowsException {
    public static void exceptionMethod () throws IllegalAccessException{
        System.out.println("Всередині exceptionMethod().");
        throw new IllegalAccessException("Помилка доступу");
          
    }
     public static void main(String args[]){
        try{
           exceptionMethod(); 
           System.out.println("Кінець програми"); //даний рядок не буде виведений
        }catch(IllegalAccessException e){
           System.out.println("Наш витяток: "+e);
        }           
    }
}

Результат:

Всередині ExceptionMethod().
Наш витяток: java.lang.IllegalAccessException: Помилка доступу

Як бачимо тепер обробка винятку відбувається у методі main(). Без інструкції try-catch програма призупинятиметься з друком відбитку стеку. Слід зауважити, що у методах інструкція throw поводить себе подібно до інструкції return. Тобто виконання методу припиняється і відбувається повернення в місце виклику методу.

Додаткові джерела[ред.]

Примітки[ред.]

  1. Java™ Platform, Standard Edition 7 API Specification (Натисніть TREE для перегляду ієрархії класів)
  2. The try-with-resources Statement

(даний розділ незавершений, потребує доповнення. Необхідно дописати: отримання інформації про винятки, зчеплення винятків, створення власних)

Об'єкти і класи · Графічний інтерфейс користувача