Назад Зміст Вперед

9.6. Оператор throw

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

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

В блоках інструкцій try об'єкти винятків створюються автоматично при виникненні помилки. Але також у мові Java є можливість створювати і передавати об'єкти винятків самостійно. Це робиться за допомогою ключового слова throw:
try {
  ...
  throw new ArithmeticException(Ділення на нуль);
}
catch(ArithmeticException vunjatok) {
  ...
}
В цьому прикладі за допомогою ключового слова new і конструктора створюється новий об'єкт класу ArithmeticException. За допомогою ключового throw новостворений об'єкт винятку передається інструкцією try та перехоплюється інструкцією catch.

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

Можливо також, щоб методи теж створювали об'єкти винятків за допомогою ключового слова throw без інструкцій try-catch:
void metod() {
  ...
  throw new ArithmeticException();
}

Якщо метод створює об'єкт винятку без інструкцій try-catch, то він обов'язково має виконуватися в інструкції try і створений виняток повинен перехоплюватися інструкцією catch, інакше виникне звичайна помилка виконання без перехоплення і програма завершить своє виконання:
try {
  ...
  metod(); // метод metod() створює виняток ArithmeticException
}
catch (ArithmeticException vunjatok) { /* ця інструкція перехоплює виняток, створений
методом metod() */
  ...
}

Створення власних винятків

Щоб створити власні винятки, потрібно оголосити клас, який буде успадковуватися від класу Exception:
package inwe;

class Vunjatok extends Exception { /* оголошується власний клас винятків шляхом успадкування від класу Exception */
  String povidomlennja;
  Vunjatok(String povid) {
    povidomlennja = povid;
  }
  public String toString() { // перевизначається метод toString()
    return povidomlennja;
  }
}

class VlasniVunjatku {
  static void stvorVunjatok() throws Vunjatok { // власні винятки завжди є перевірними
    throw new Vunjatok(Виняток всередині stvorVunjatok());
  }
  public static void main(String args[]) {
    int x;
    try {
      for(x = 0; x < 15; x++) {
        System.out.println(x);
        if(x == 9) throw new Vunjatok(Виняток після дев'ятки); /* тепер можна створити об'єкт власного винятку */
      }
    }
    catch(Vunjatok vunjatok) {
      System.out.println(vunjatok);
    }
    try {
      stvorVunjatok();
    }
    catch(Vunjatok vunjatok) {
      System.out.println(vunjatok);
    }
  }
}
Результат:
0
1
2
3
4
5
6
7
8
9
Виняток після дев'ятки
Виняток всередині stvorVunjatok()

В цій програмі оголошується новий клас винятків Vunjatok. В програмі об'єкти винятків класу Vunjatok створюються двома способами: всередині блоку try та всередині методу stvorVunjatok(). Об'єкти винятків новоствореного класу працюють так само, як і перевірних вбудованих винятків Java.
За допомогою ключового слова throw можна створювати об'єкти тільки похідних винятків від Throwable або Exception класів. В іншому випадку програма виведе повідомлення про помилку.

Успадковані методи власних винятків

Створені програмістом винятки успадковують від класу Thorwable різні методи. Ось деякі з них(докладніше тут):
  • String getMessage() — метод повертає детальний опис даного винятку;
  • String toString() — метод повертає короткий опис даного винятку;
  • Throwable initCause(Throwable pruquna) — метод пов'язує викликаючий виняток із винятком pruquna як із причиною викликаючого винятку. Повертає посилання на виняток pruquna:
  • Throwable getCause() — повертає причину-виняток даного винятку або null, якщо виняток-причина не відомий або його не існує;

Інструкція try-with-resources

Починаючи із JDK 7 в Java з'явилася нова можливість використання інструкції try — try-with-resources(спроба-із-запасами):
try(ініціалізація об'єкту) {
  ...
}

В параметрах інструкції try-with-resources можуть ініціалізуватися об'єкти класів, що реалізують інтерфейс java.lang.AutoCloseable. Повний список цих класів знаходиться тут

Перевага інструкції try-with-resources в тому, що ініціалізовані в параметрах об'єкти після завершення виконання блоку інструкції автоматично закриваються та звільняють зайняту для їх роботи пам'ять. Це дозволяє уникнути помилок, коли програміст забуває закрити об'єкт і в програмі з'являється надлишкова зайнята пам'ять. При використанні звичайної інструкції try, щоб закрити об'єкти, використовують інструкцію finally:
...
int zminna;
// Створення об’єкту
Scanner vvid = new Scanner(System.in);
...
try {
  zminna = vvid.nextInt(); // використання об'єкту vvid
  ...
}
catch(...) { // перехоплення об'єктів винятків
  ...
}
finally {
  ...
  vvid.close(); // закривання об'єкту vvid, звільнення пам'яті
}

При використанні інструкції try-with-resources інструкцію finally не застосовують для закривання об'єкту, тому програмний код стає меншим та зрозумілішим.

Ось програма, яка показує використання інструкції try-with-resources (TryWithResources.java):
package inwe;
import java.util.Scanner; // імпортується клас для введення даних у консоль
import java.util.InputMismatchException; /* імпортується виняток помилки
введення відповідних даних */


class TryWithResources {
  public static void main(String args[]) {
    double quslo = 1;
   
    try(Scanner vvid = new Scanner(System.in)) { /* в параметрах try-with-resources  ініціалізуються об'єкти класів, що реалізують інтерфейс java.lang.AutoCloseable */
      for(;;) {
        System.out.println(Введіть число для піднесення до квадрату(0 для виходу): );
        quslo = vvid.nextDouble();
        if(quslo == 0) {
          System.out.println(Вихід);
          return;
        }
        System.out.println(Квадрат числа  + quslo +  дорівнює  + (quslo * quslo));
      }
    } /* після завершення виконання блоку try-with-resources об'єкти, оголошені в параметрах, автоматично закриваються та звільняють пам'ять */
    catch(InputMismatchException vunjatok) { // введені дані не числового типу
      System.out.println(Введені неправильні дані);
    }
  }
}
Можливий результат виконання:
Введіть число для піднесення до квадрату(0 для виходу):
2
Квадрат числа 2.0 дорівнює 4.0
Введіть число для піднесення до квадрату(0 для виходу):
7
Квадрат числа 7.0 дорівнює 49.0
Введіть число для піднесення до квадрату(0 для виходу):
0
Вихід
В наведеному прикладі не застосовується інструкція finally з методом close() для закривання об'єкту, об'єкт автоматично закривається після завершення виконання інструкції try-with-resources.

Всі об'єкти, оголошені в параметрах інструкції try-with-resources, неявно оголошуються фінальними, тобто оголошеній в параметрах об'єктній змінній(посиланню) не можна присвоїти інший об'єкт. Також ініціалізовані в параметрах цієї інструкції об'єкти будуть виконуватися лише всередині її тіла(блоку).

В параметрах інструкції try-with-resources можна ініціалізовувати кілька об'єктів. Для цього ініціалізації за допомогою символа ; :
try(ініціалізація_об'єкту1; ініціалізація_об'єкту2; ...) {
  ...
}

Приклад:
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.

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