JavaRush /Java блог /Java Developer /Винятки: checked, unchecked і свої власні
Автор
Владимир Портянко
Java-разработчик в Playtika

Винятки: checked, unchecked і свої власні

Стаття з групи Java Developer
Привіт! У минулій лекції ми познайомилися з таким аспектом мови Java як винятки і побачили приклади роботи з ними. Сьогодні ми глибше розглянемо їхню структуру, а також навчимося писати власні винятки :)

Види винятків

Як ми й казали, класів-винятків у Java дуже багато, майже 400! Але всі вони поділяються на групи, тож запам'ятати їх досить легко. Ось як це виглядає: Винятки: checked, unchecked і свої власні - 2У всіх винятків є загальний клас-предок Throwable. Від нього походять дві великі групи – винятки (Exception) і помилки (Error). Error – це критична помилка під час виконання програми, пов'язана з роботою віртуальної машини Java. У більшості випадків Error не потрібно обробляти, оскільки вона свідчить про якісь серйозні недоробки в коді. Найвідоміші помилки: StackOverflowError – виникає, наприклад, коли метод нескінченно викликає сам себе, і OutOfMemoryError – виникає, коли недостатньо пам'яті для створення нових об'єктів. Як бачиш, у цих ситуаціях найчастіше обробляти особливо нічого – код просто неправильно написаний і його потрібно переробляти. Exceptions – це, власне, винятки: виняткова, незапланована ситуація, яка сталася під час роботи програми. Це не такі серйозні помилки, як Error, але вони вимагають нашої уваги. Усі винятки поділяються на 2 види – що перевіряються (checked) і що не перевіряються (unchecked). Винятки: checked, unchecked і свої власні - 3Всі винятки, що перевіряються, походять від класу Exception. Що значить "що перевіряються"? Ми частково згадували про це в минулій лекції: "...компілятор Java знає про найпоширеніші винятки, і знає, у яких ситуаціях вони можуть виникнути". Наприклад, він знає, що якщо програміст у коді зчитує дані з файлу, може легко виникнути ситуація, що файл не існує. І таких ситуацій, які він може заздалегідь передбачити, дуже багато. Тому компілятор заздалегідь перевіряє наш код на наявність потенційних винятків. Якщо він їх знайде, то не скомпілює код, поки ми не опрацюємо їх або не прокинемо нагору. Другий вид винятків – "що не перевіряються". Вони походять від класу RuntimeException. Чим же вони відрізняються від тих, що перевіряються? Здавалося б, теж є купа різних класів, які походять від RuntimeException і описують конкретні runtime-винятки. Різниця в тому, що цих помилок компілятор не очікує. Він ніби говорить: "На момент написання коду я нічого підозрілого не виявив, але під час його роботи щось пішло не так. Мабуть, у коді є помилки!" І це дійсно так. Винятки, що не перевіряються, найчастіше є наслідком помилок програміста. А компілятор явно не в змозі передбачити всі можливі неправильні ситуації, які люди можуть створити своїми руками :) Тому він не перевірятиме обробку таких винятків у нашому коді. Ти вже стикався з кількома винятками, що не перевіряються:
  • ArithmeticException виникає під час ділення на нуль
  • ArrayIndexOutOfBoundsException виникає при спробі звернутися до комірки за межами масиву.
Теоретично, звісно, творці Java могли б запровадити обов'язкову обробку таких винятків, але на що б тоді перетворився код? За будь-якої операції ділення чисел довелося б писати try-catch для перевірки – чи не на нуль ти випадково ділиш? У разі будь-якого звернення до масиву треба було б писати try-catch, щоб перевірити, чи не вийшов ти за ці межі. Будь-який написаний код являв би собою спагеті і був би абсолютно нечитабельним. Логічно, що від цієї ідеї відмовилися. Тому винятки, що не перевіряються, не потрібно обробляти в блоках try-catch або прокидати нагору, хоча технічно це можливо, як і з Error. Винятки: checked, unchecked і свої власні - 3

Як викинути свій виняток

Очевидно, творці Java не в змозі передбачити всі виняткові ситуації, які можуть виникнути в програмах. Програм у світі занадто багато, і вони занадто різні. Але це не страшно, оскільки у разі потреби ти можеш створювати власні винятки. Це робиться дуже легко. Тобі достатньо створити власний клас. Його назва має закінчуватися на "Exception". Компілятору це не потрібно, але програмістам, які читають твій код, одразу буде зрозуміло, що це клас-виняток. Крім того, потрібно вказати, що клас походить від класу Exception. Це вже потрібно для компілятора і коректної роботи. Наприклад, у нас є клас Собака – Dog. Ми можемо погуляти з собакою за допомогою методу walk(). Але перед цим нам потрібно перевірити, чи надіті на нашого вихованця нашийник, повідець і намордник. Якщо щось із цього відсутнє, викинемо власний виняток DogIsNotReadyException. Його код матиме такий вигляд:

public class DogIsNotReadyException extends Exception { 

   public DogIsNotReadyException(String message) { 
       super(message); 
   } 
} 
Щоб вказати, що клас є винятком, потрібно написати extends Exception після імені класу: це означає, що "клас походить від класу Exception". У конструкторі ми просто викличемо конструктор класу Exception з рядком message – він відображатиме користувачеві повідомлення від системи з описом помилки, що виникла. Ось який вигляд це матиме в коді нашого класу:

public class Dog { 

   String name;
   boolean isCollarPutOn; 
   boolean isLeashPutOn; 
   boolean isMuzzlePutOn; 

   public Dog(String name) { 
       this.name = name; 
   } 

   public static void main(String[] args) { 

   } 

   public void putCollar() { 

       System.out.println("Нашийник надітий!"); 
       this.isCollarPutOn = true; 
   } 

   public void putLeash() { 

       System.out.println("Повідець надітий!"); 
       this.isLeashPutOn = true; 
   } 

   public void putMuzzle() { 
       System.out.println("Намордник надітий!"); 
       this.isMuzzlePutOn = true; 
   } 

   public void walk() throws DogIsNotReadyException { 

   System.out.println("Збираємося на прогулянку!"); 
   if (isCollarPutOn && isLeashPutOn && isMuzzlePutOn) { 
       System.out.println("Ура, ідемо гуляти! " + name + " дуже радий!"); 
   } else { 
       throw new DogIsNotReadyException("Собака " + name + " не готовий до прогулянки! Перевірте екіпірування!"); 
   } 
 } 

} 
Тепер наш метод walk() викидає виняток DogIsNotReadyException. Це робиться за допомогою ключового слова throw. Як ми вже казали раніше, виняток – це об'єкт. Тому в нашому методі в разі виникнення виняткової ситуації – на собаці чогось не вистачає – ми створюємо новий об'єкт класу DogIsNotReadyException і викидаємо в програму за допомогою слова throw. До сигнатури методу walk() ми додаємо throws DogIsNotReadyException. Іншими словами, тепер компілятор в курсі, що виклик методу walk() може обернутися винятковою ситуацією. Тому коли ми викличемо це десь у програмі, виняток потрібно буде обробити. Спробуємо зробити це в методі main():

public static void main(String[] args) { 

   Dog dog = new Dog("Мухтар"); 
   dog.putCollar(); 
   dog.putMuzzle(); 
   dog.walk();//Unhandled exception: DogIsNotReadyException 
} 
Не компілюється, виняток не оброблено! Обернемо наш код у блок try-catch для обробки винятку:

public static void main(String[] args) { 

   Dog dog = new Dog("Мухтар"); 
   dog.putCollar(); 
   dog.putMuzzle(); 
   try { 
       dog.walk();
   } catch (DogIsNotReadyException e) { 
       System.out.println(e.getMessage()); 
       System.out.println("Перевіряємо спорядження! Нашийник надітий? " + dog.isCollarPutOn + "\r\n Повідець надітий? " 
       + dog.isLeashPutOn + "\r\n Намордник надітий? " + dog.isMuzzlePutOn); 
   } 
} 
Тепер подивимося на виведення в консоль:
Нашийник надітий! Намордник надітий! Збираємося на прогулянку! Собака Мухтар не готовий до прогулянки! Перевірте екіпірування! Перевіряємо спорядження! Нашийник надітий? true Повідець надітий? false Намордник надітий? true
Подивися, наскільки більш інформативним стало виведення в консоль! Ми бачимо кожен крок, який відбувався в програмі; бачимо, в якому місці виникла помилка, і одразу помічаємо, чого саме не вистачає нашому собаці :) Ось так і створюються власні винятки. Як бачиш, нічого складного. І хоча розробники Java не спромоглися додати у свою мову спеціальний виняток для неправильно екіпірованих собак, ми виправили їхню помилку :)
Коментарі (4)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Viacheslav B. Рівень 19
21 березня 2024
дяка, тут я нарешті більше зрозумів що означає (checked) та (unchecked).
Sava_crosava Рівень 23
23 жовтня 2023
Був приємно вражений статті українською мовою, дукую за рух в перед)
Pavlo Kezin Рівень 23
17 вересня 2023
гарна лекція.
Mister Dream47 Рівень 11
25 лютого 2023
Дякую, за ваш український! Бачу, що перейти на цю мову вашій платформі складно. А ви не можете зробити, щоб була змога вибирати мову ваших лекцій, чи писати на двох мовах? Дуже хочу, щоб українці підключились масово до вашого продукту! Мені подобається JavaRush👍😉