JavaRush /Курси /Java Syntax Zero /Виключення в Java-програмах

Виключення в Java-програмах

Java Syntax Zero
Рівень 15 , Лекція 2
Відкрита

1. Винятки

Винятки у Java-програмах

Нарешті програмісти здогадалися регламентувати та автоматизувати обробку помилок. Сталося це, коли винайшли винятки. Зараз за допомогою механізму винятків у світі обробляється 80% нестандартних ситуацій.

Якщо винятки вигадав якийсь учений, то, скоріш за все, він захистив на цьому докторську дисертацію. Якщо ж вигадав програміст, то він, можливо, отримав дружнє поплескування по плечу від колег: «Наче норм, бро».

Коли у Java-програмі виникає помилка, наприклад, ділення на 0, відбуваються такі чудові речі:

Крок перший

Створюється спеціальний об'єкт-виняток, у якому міститься інформація про помилку, що сталася.

Усе в Java є об'єктом, і винятки — не виняток 🙂 Об'єкти-винятки мають свої класи, і вся їхня відмінність від звичайних класів у тому, що вони успадковані від класу Throwable.

Крок другий

Об'єкт-виняток «викидається». Не дуже вдале визначення. «Викидання винятку» по суті більше схоже на включення пожежної сигналізації або сповіщення «бойова тривога».

Коли в систему «викинуто виняток», нормальний режим роботи програми припиняється, і починається «робота за аварійним протоколом».

Крок третій

Поточний метод, у якому виник (викинуто) виняток, негайно завершується. Виняток передається у викликаючий метод, який також негайно завершується. І так по ланцюжку, поки не завершиться метод main. Разом із завершенням методу main завершується і програма.

Приклад:

Код Вивід на екран
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Увага! Підготовка до кінця світу");
      кінецьСвіту();
      System.out.println("Кінець світу успішно завершено");
   }

   public static void кінецьСвіту()
   {
      System.out.println("Робимо щось важливе");
      поділимо(0);
      System.out.println("Все чудово працює");
   }

   public static void поділимо(int n)
   {
      System.out.println("Нічого страшного не станеться: " + n);
      System.out.println(2 / n);
      System.out.println("Нічого страшного не сталося: " + n);
   }
}
Увага! Підготовка до кінця світу
Робимо щось важливе
Нічого страшного не станеться: 0

На 20-й стрічці виникла помилка — ділення на 0. Java-машина тут же створила виняток — об'єкт класу ArithmeticException і «викинула» його в систему.

Метод поділимо() відразу завершився, тому на екран не вивелась стрічка Нічого страшного не сталося: 0. Програма повернулася в метод кінецьСвіту(), і ситуація повторилась: у системі є виняток, а значить, метод кінецьСвіту() також аварійно завершується. Потім завершується метод main, і виконання програми припиняється.

А в чому ж сенс роботи таких винятків? А в тому, що у вашій програмі можна перехоплювати винятки певного типу і написати свою логіку обробки аварійних ситуацій.


2. Перехоплення винятків try-catch

У Java є механізм перехоплення винятків, який дозволяє припинити аварійне завершення методів. Виглядає він ось так:

try
{
   код, де може виникнути помилка
}
catch(ТипВинятку ім'я)
{
   код обробки винятку
}

Ця конструкція називається блок try-catch.

Код, в якому можуть виникнути винятки, обгортається у фігурні дужки, перед якими пишеться слово try (спробувати).

Після фігурних дужок пишеться ключове слово catch, всередині круглих дужок оголошується змінна типу-винятку. Далі йдуть фігурні дужки, всередині яких пишеться код, який потрібно виконати, якщо виникне виняток зазначеного типу.

Якщо під час виконання «основного коду» винятків не виникло, код всередині блоку catch виконуватися не буде. Якщо ж виняток виник, блок catch виконається (за умови, що тип виниклого винятку збігається з типом змінної у круглих дужках).

Приклад:

Код Вивід на екран
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Адронний Колайдер запущено");

      try
      {
         запуститиАдроннийКолайдер(1);
         запуститиАдроннийКолайдер(0);
      }
      catch(Exception e)
      {
         System.out.println("Помилка! Перехоплено виняток");
         System.out.println("Планету затягнуло в чорну діру!");
      }

      System.out.println("Адронний Колайдер зупинено");
   }

   public static void запуститиАдроннийКолайдер(int n)
   {
      System.out.println("Все чудово працює: " + n);
      System.out.println(2/n);
      System.out.println("Жодних проблем немає: " + n);
   }
}
Адронний Колайдер запущено
Все чудово працює: 1
2
Жодних проблем немає: 1
Все чудово працює: 0
Помилка! Перехоплено виняток
Планету затягнуло в чорну діру!
Адронний Колайдер зупинено


3. Кілька блоків catch

Кілька блоків catch

Теоретично всередині блоку коду можуть виникати дуже різні виключення. Деякі ви захочете обробити одним способом, інші — іншим, треті взагалі вирішите не обробляти.

Розробники Java вирішили допомогти вам і дозволили писати після блоку try не один блок catch, а кілька.

try
{
   код, де може виникнути помилка
}
catch(ТипВиключення1 ім'я1)
{
   код обробки виключення1
}
catch(ТипВиключення2 ім'я2)
{
   код обробки виключення2
}
   catch(ТипВиключення3 ім'я3)
{
   код обробки виключення3
}

Приклад:

Код Вивід на екран
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Початок методу main");
      try
      {
         calculate(0);
      }
      catch(ArithmeticException e)
      {
         System.out.println("Було ділення на 0");
      }
      catch(Exception e)
      {
         System.out.println("Перехоплено якесь виключення");
      }

      System.out.println("Кінець методу main");
   }

   public static void calculate(int n)
   {
      System.out.println("calculate початок: " + n);
      System.out.println(2/n);
      System.out.println("calculate кінець: " + n);
   }
}
Початок методу main
calculate початок: 0
Було ділення на 0
Кінець методу main


4. Порядок блоків catch

Виняток, що виник у блоці try, може бути перехоплений лише одним блоком catch. Не може бути ситуації, коли при обробці винятку виконується код із кількох блоків catch.

Однак порядок блоків має значення.

Може бути ситуація, коли виняток перехоплено кількома блоками. У цьому випадку він буде перехоплений блоком catch, який йде раніше (ближче до блоку try).

Як же може виникнути ситуація, що один виняток можуть перехопити кілька блоків catch?

Усі винятки об'єднані в єдину ієрархію за допомогою успадкування — дивися схему.

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

Об'єкт-виняток типу ArithmeticException може бути присвоєно змінній типу ArithmeticException, а також змінним його класів-батьків: RuntimeException, Exception і Throwable — дивися схему.

Детальніше про успадкування та класи-батьки ми поговоримо на 21 рівні.

Ось цей код буде чудово компілюватися:

Переваги успадкування:
ArithmeticException ae    = new ArithmeticException();
RuntimeException runtime  = new ArithmeticException();
Exception exception       = new ArithmeticException();
Throwable trwbl           = new ArithmeticException();

Тому і перехопити виняток типу ArithmeticException можна блоками catch будь-якого з 4-х наведених вище типів.

Приклад 1:

Код Вивід на екран
class Solution
{    public static void main(String[] args)
   {
      System.out.println("Початок методу main");
      try
      {
         calculate(0);
      }
      catch(ArithmeticException e)
      {
         System.out.println("Було ділення на 0");
      }
      catch(Exception e)
      {
         System.out.println("Перехоплено якесь виключення");
      }

      System.out.println("Кінець методу main");
   }

   public static void calculate(int n)
   {
      System.out.println("calculate початок: " + n);
      System.out.println(2/n);
      System.out.println("calculate кінець: " + n);
   }
}
Початок методу main
calculate початок: 0
Було ділення на 0
Кінець методу main

У цьому прикладі виняток ArithmeticException може бути перехоплено як блоком catch(Exception e), так і блоком catch(ArithmeticException e). Він буде перехоплений тим блоком, який розташований ближче до блоку try — першим блоком catch.

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

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


Коментарі (8)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
4 березня 2023
"Докладніше про успадкування та класи-предки ми поговоримо на 21-му рівні." Так ми саме на рівні 21, може саме час докладніше поговорити, чи це виходить, що поговорімо про це докладніше на сторінці НІДЕ ))
𝙈𝙖𝙠𝙨𝙞𝙢 Рівень 108 Expert
17 квітня 2023
21 рівень в syntax pro це 1 рівень java core . тобто в 29 буде докладніше
Володимир Рівень 108 Expert
20 травня 2023
в джава університеті лекція така сама як і у звичайному syntaxі, а нумерація лекцій інша))
Yaroslav Tkachyk Рівень 23 Expert
11 січня 2023
System.out.println("Усе чудово працює: " + n); System.out.println(2/n); System.out.println("Жодної проблеми немає: " + n); Так при відсутності винятку, має виводитись всі три рядки: Усе чудово працює: 1 2 Жодної проблеми немає: 1
Roma Chernesh Рівень 16
16 лютого 2023
згода)
les_yeux_blancs Рівень 50
28 квітня 2023
взагалі ні, виникнення винятку зупиняє виконання і починає "розкручувати стек викликів", який власне можна знайти в нижче за саму помилку в консолі
Vlad Рівень 17
30 листопада 2023
Виконання поточного методу, в якому виник (викинуто) виняток, негайно завершується. Виняток передається в метод, звідки відбувся виклик, і робота цього методу теж негайно завершується. І так ланцюжком, доки не завершиться метод main. Одночасно з завершенням методу main завершується і програма. Тому цей метод зупинився і перейшов до конструкції try-catch а з try-catch у main. Я це так розумію.
FAUST_ua Рівень 29
6 вересня 2022
А де task1405?