Рубріки: Теорія

Винятки в Java — пояснення та приклади

Андрій Денисенко

Що таке виняток у Java (Java Exception)?

Виняток – це небажана ситуація, що виникає під час виконання програми та порушує нормальний перебіг її роботи.

Така ситуація може виникнути, наприклад, через спробу читання з файлу, якого не існує, ділення на нуль, збій пристрою тощо. Виняток можна перехопити, щоб вжити відповідних заходів.

Наведемо приклад коду, у якому виникає виняток.

class ExceptionTest{ 
    // Метод приймає два цілих числа
    // та повертає результат поділу
    // першого на друге
    static float divide(int x, int y){
        float result = x / y;
        return result;
    }

    public static void main(String args[]){
        // Ця стрічка буде виконана 
        System.out.println(divide(4, 2));
        // Ця теж
        System.out.println(divide(0, 2));
        // Ця викине виняток
        System.out.println(divide(4, 0));
    }
}

Якщо його запустити, отримаємо наступний результат:

2.0
0.0
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at ExceptionTest.divide(ExceptionTest.java:6)
        at ExceptionTest.main(ExceptionTest.java:16)

Виводяться два результати ділення та повідомлення про виняток. У цьому повідомленні вказано таку інформацію:

  • тип винятку (ArithmeticException);
  • який саме виняток виник (розподіл на нуль);
  • стек виконання: методи та рядки, у яких виник виняток.

Оператори try, catch, finally, throw, throws: обробка винятків та приклади використання

Для перехоплення виняткових ситуацій створюється об’єкт винятку, що передається середовищу виконання. Він містить інформацію про помилку, зокрема її тип та стан програми на момент виникнення помилки. Створення об’єкта винятку та його передача середовищу виконання називається викиданням виняткової ситуації.

try-catch

Для перехоплення винятку використовується конструкція trycatch. Код, який потрібно перевірити на виняток, розміщено в блоці try, а код, що обробляє виняток, – у блоці catch.

Додамо ці блоки до наведеного вище блоку коду і доповнимо його парою змінних для наочності.

class ExceptionTest{  
    // Метод принимает два целых числа
    // и возвращает результат деления
    // первого на второе
    static float divide(int x, int y){
        float result = x / y;
        return result;
    }

    public static void main(String args[]){
        int x = 4;
        int y = 2;
        try {
            // Эта строка будет выполнена
            System.out.println(divide(x, y));

            x = 0;
            // Эта тоже
            System.out.println(divide(x, y));

            x = 4;
            y = 0;
            // Эта выбросит исключение
            System.out.println(divide(x, y));
        } catch (ArithmeticException e) {
            System.out.println("Ошибка при делении " + x + " на " + y);
        }
    }
}

Отримаємо більш зручний для читання результат:

2.0
0.0
Помилка ділення 4 на 0

finally

Блок finally виконується після try-catch незалежно від того, чи виник виняток. Це необов’язковий блок, але якщо немає блоку catch, то блок finally необхідний.

У цьому блоці можна, наприклад, закрити файл, який відкрито в блоці try, як у наведеному нижче коді.

import java.io.FileWriter;
import java.io.IOException;

public class FinallyTest {
    public static void main(String[] args) {
        FileWriter writer = null;
        try {
            writer = new FileWriter("out.txt");
            writer.write("Writing to the file!");
            System.out.println("Файл записаний вдало.");
        } catch (IOException e) {
            System.out.println("Помилка запису у файл.");
            e.printStackTrace();
        } finally {
            if ( writer != null ){
                try{
                  writer.close();
                } catch (IOException e) {
                  System. out.println("Помилка закриття файла.");
                  e.printStackTrace();
                }
            }
        }
    }
}

throw

У деяких випадках потрібно викинути виняток самостійно. Це робиться за допомогою ключового слова throw .

У цьому прикладі метод PrintMe викидає виняток, якщо його аргумент дорівнює null.

import java.util.LinkedList;

public class ThrowTest
{
  public static void main(String[] args) {
        LinkedList<String> fruits = new LinkedList<String>();
        fruits.add("apple");
        fruits.add("banana");
        fruits.add("orange");
        fruits.add("mango");

        // Печатает список
        ThrowTest.PrintMe(fruits);

        // Выбрасывает исключение
        ThrowTest.PrintMe(null);
  }

    public static void PrintMe(LinkedList<String> fruits){
        if (fruits == null){
            throw new NullPointerException("Аргумент не инициализирован");
        }
        System.out.println(fruits);
    }
}

Ієрархія винятків Java

Винятки в Java поділяються на дві основні категорії: вбудовані та користувацькі.

Вбудовані винятки

Вбудовані винятки – це винятки, які визначено в Java.

Коли виникає вбудований виняток, віртуальна машина Java (JVM) створює об’єкт, що належить класу вбудованого винятку. Усі винятки походять від класу java.lang.Throwable, але їх визначено в кількох пакетах.

Клас Throwable походить безпосередньо від класу Object і є кореневим класом дерева класів винятків. Від нього походять два підкласи: Error та Exception. Помилки й винятки, які зустрічаються в програмах Java, є об’єктами цих класів.

За допомогою класу Throwable можна створювати власні винятки.

Клас Error є надкласом всім класів помилок часу виконання. Він завершує виконання програми, якщо відбувається помилка, пов’язана із системою або ресурсами (JVM).

Помилка зазвичай є незвичайною проблемою, після якої складно здійснити відновлення. Вони відбуваються не з вини програміста, а через неналежну роботу системи або виділення ресурсів.

Приклади помилок: AssertionError, LinkageError, OutOfMmeoryError, StackOverFlowError, VirtualMachineError.

Клас Exception представляє помилки, які спричинено програмою чи зовнішніми чинниками. Це надклас для всіх класів винятків.

Для цього класу існує два конструктори:

  • public Exception() (за замовчуванням)
  • public Exception(String message) (приймає рядкове повідомлення як аргумент)

Ці конструктори успадковуються всіма підкласами винятків. Сам собою клас Exception не надає своїх методів. Він успадковує методи класу Throwable.

Вбудовані винятки поділяються на дві групи: перевірювані (checked) та неперевірювані (unchecked).

Перевірювані винятки Java

Переваірювані винятки перевіряються компілятором Java під час компіляції і не є підкласами RuntimeException (винятку часу виконання).

Якщо метод викидає перевірюваний виняток, то цей виняток необхідно обробити або в цьому самому методі, або передати методу, який його викликав.

Перевірювані винятки обробляються або в блоці try-catch, або в оголошенні методу з ключовим словом throws. Якщо виняток не опрацьовано, відбувається помилка компіляції.

Перевіреними винятками є всі винятки, крім RuntimeException, Error та його підкласів.

Приклади винятків, що перевіряються: ClassNotFoundException, IOException, SQLException, IllegalAccessException, FileNotFoundException.

Неперевірювані винятки (винятки часу виконання) в Java

Неперевірювані винятки в Java – це винятки, які перевіряються JVM, а не компілятором Java. Вони виникають під час виконання програми.

Усі підкласи RuntimeException називаються неперевіреними винятками або винятками часу виконання в Java.

Можна написати програму на Java й скомпілювати її, але ми не побачимо неперевірених виключень і помилок, поки не запустимо цю програму.

Компілятор Java не перевіряє винятки часу виконання під час компіляції, незалежно від того, чи обробляє їх програма.

Якщо в методі виникає виняток часу виконання, а програміст не обробляє його, JVM припиняє виконання програми та не виконує остаток коду.

Приклади неперевірюваних винятків: ArithmeticException, ArrayIndexOutOfBoundsException, ClassCastException, NegativeArraySizeException, NullPointerException.

У Java визначено багато вбудованих винятків. Нижче наведено описи деяких з них.

Виняток Опис
ArithmeticException Викидається, коли виникає виняткова арифметична ситуація.
ArrayIndexOutOfBoundsException Викидається під час спроби звернутися до масиву за недійсним індексом.
ArrayStoreException Викидається під час спроби зберегти об’єкт невідповідного типу в масиві об’єктів.
ClassCastException Викидається, коли код здійснює спробу привести тип об’єкта до підкласу, екземпляром якого він не є.
ClassNotFoundException Викидається, коли програма намагається завантажити клас за його ім’ям у рядковому поданні з використанням методу forName у класі Class.
CloneNotSupportedException Викидається, коли для клонування об’єкта певного класу викликано метод clone, але клас цього об’єкта не реалізує інтерфейс Cloneable.
EnumConstantNotPresentException Викидається, коли програма намагається звернутися до константи з переліку на ім’я, але тип цього переліку не містить константу з зазначеним ім’ям.
Виняток Клас Exception та його підкласи є підкласами Throwable та вказують на ситуації, які можуть бути перехоплені програмою.
IllegalAccessException Викидається, коли програма намагається застосувати рефлексію, щоб створити примірник (відмінний від масиву), призначити полю значення або отримати значення поля, викликати метод, але поточний метод не має доступу до визначення зазначеного класу, поля, методу чи конструктора.
IllegalArgumentException Викидається, коли методу передано неприпустимий чи неприйнятний аргумент.
IllegalMonitorStateException Викидається, коли нитка намагається очікувати на монітор об’єкта або надіслати сповіщення іншим ниткам, які чекають на монітор об’єкта, але вказаний монітор не належить їй.
IllegalStateException Викидається, коли метод викликано в неприпустимий або неприйнятний час.
IllegalThreadStateException Викидається, коли нитка знаходиться в неприйнятному стані для виконання цієї операції.
IndexOutOfBoundsException Викидається, коли індекс певного типу (наприклад, для масиву, рядка або вектора) знаходиться поза допустимим діапазоном.
InstantiationException Викидається, коли програма намагається створити екземпляр класу з використанням методу newInstance класу Class, але створити екземпляр зазначеного класу неможливо.
InterruptedException Викидається, коли нитка перебуває в стані очікування, сну або зайнята іншими діями, але її роботу перервано перед виконанням дії чи після її виконання.
Виняток NegativeArraySize Викидається, коли програма робить спробу створити масив негативного розміру.
NoSuchFieldException Викидається, коли в класі немає поля з зазначеним ім’ям.
NoSuchMethodException Викидається, коли неможливо знайти вказаний метод.
NullPointerException Викидається, коли програма намагається використовувати значення null, але потрібно вказати об’єкт.
NumberFormatException Викидається, коли програма намагається перетворити рядок на один із числових типів, але рядок має неприпустимий формат.
RuntimeException Це батьківський клас для тих винятків, які можуть бути викинуті за нормальної роботи віртуальної машини Java.
SecurityException Викидається менеджером безпеки у випадку порушення безпеки.
StringIndexOutOfBoundsException Викидається методами класу String під час спроби використати негативний індекс або індекс, що перевищує розмір рядка.
TypeNotPresentException Викидається, коли програма намагається отримати доступ до типу з зазначенням його імені у вигляді рядка, але не вдається знайти визначення типу зі вказаним ім’ям.
UnsupportedOperationException Викидається, коли запитана операція не підтримується.

Користувацькі винятки

Користувацькі винятки створюються користувачами або програмістами відповідно до їх власних потреб. Їх створюють розширенням класу Exception.

Прикладом винятку може бути ситуація, коли користувач намагається відкрити банківський рахунок, але не досяг віку 18 років. У такому разі може бути видано повідомлення про те, що потрібно відкрити рахунок із кимось із батьків. 

Щоб використовувати користувацький виняток, потрібно виконати наступні дії.

  • Визначити клас, який розширює клас Exception.
  • Визначити конструктор. Якщо не потрібно зберігати відомості про виняток, визначається стандартний конструктор. Якщо потрібно зберегти інформацію про виняток як рядок, визначається конструктор з параметром.
  • Створити об’єкт користувацького винятку й викинути його за допомогою ключового слова throw.

Приклад винятку з конструктором за замовчуванням:

class MyException extends Exception{
    // Конструктор по умолчанию
    MyException(){}
}

class Main{
    public static void main(String[] args){
        try{
            MyException e = new MyException();
            throw e;
        }
        catch(MyException ex){
             System.out.println("Перехоплено користувацьке виключення"); 
        }
    }
}

Цей код виведе наступний текст: ” Перехоплено виняток користувача”.

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

class MyException extends Exception{
    MyException(String msg){
        super(msg);
    }
}

class Main{
    public static void main(String[] args){
        try{
            MyException e = new MyException("Перехоплено користувацьке виключення з інформацією");
            throw e;
        }
        catch(MyException ex){
             System.out.println(ex.getMessage()); 
        }
    }
}

Буде виведено такий текст: “Перехоплено виняток користувача з інформацією”

Висновок

Винятки Java дозволяють зазначити шляхи обходу проблем і виправлення їх наслідків. З їхньою допомогою можна помістити логіку обробки виняткових ситуацій в окремі блоки коду (catch), залишивши основну логіку в блоці try, а логіку завершальних дій з обробки винятку – у блоці finally. Винятки можуть бути оброблені в методах, де вони виникають, або передані далі за допомогою ключових throw та throws.

Java надає великий набір вбудованих винятків, а також дає програмісту гнучкість, дозволяючи створювати власні винятки відповідно до потреб програми.

Останні статті

SET University пропонує військовим та їх родинам безплатну магістратуру за 4 спеціальностями

Некомерційний навчальний заклад SET University запускає стипендійну програму за рядом напрямків. Українці та українки можуть…

29.04.2024

Від РЕБ до «плащів-невидимок»: за рік в рамках Brave1 створили 1 671 інноваційну розробку

За рік в рамках defense-tech кластеру Brave1 963 розробники створили 1 671 інноваційну розробку —…

29.04.2024

Треба «дешева» робоча сила: Google повністю звільнила команду Python в США

Корпорація Google звільнила всю команду Python в США. Про це стало відомо з публікації Social.coop…

29.04.2024

Українські школярі перемогли на міжнародному ШІ-хакатоні зі застосунком для вивчення жестової мови

Команда з ліцею КПІ PL of KPI Igor Sikorsky перемогла на міжнародному хакатоні зі штучного…

29.04.2024

Більше 50% Go i Ruby розробників з досвідом 3+ роки найняли на $5000. PHP — на самому дні

Більше половини Go i Ruby розробників з досвідом 3+ роки найняли на $5000 або більше.…

26.04.2024

Програмісти намагалися втекти з України в Молдову, щоб влаштуватись на роботу

Прикордонники недалеко від с. Кучурган Одеської області затримали двох програмістів, які намагалися втекти з України…

26.04.2024