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

Лабораторна робота «Використання оператора throws в методах із контрольованими та неконтрольованими винятками»

Винятки - це спеціальний механізм для контролю над помилками в програмі. Ось приклади помилок, які можуть виникнути в програмі:
  1. Програма намагається записати файл на заповнений диск.
  2. Програма намагається викликати метод у змінної, яка зберігає посилання - null.
  3. Програма намагається розділити число на 0.

Всі ці дії призводять до виникнення помилки. Зазвичай це призводить до закриття програми - продовжувати виконувати далі код не має сенсу.

Механізм обробки помилок:
  1. Коли виникає помилка, Java-машина створює спеціальний об'єкт - exception - виняток, в який записується вся інформація про помилку. Для різних помилок є різні винятку.
  2. Потім це «виключення» призводить до того, що програма тут же виходить з поточної функції, потім виходить з наступної функції, і так поки не вийде з методу main. Потім програма завершується. Ще кажуть, що Java-машина «розкручує тому стек викликів».
Для обробки винятків є спеціальна конструкція try-catch. Ось як це працює: 
Ось приклад програми, яка перехоплює виняток - ділення на 0. І продовжує працювати.

public class ExceptionExample2
{
    public static void main(String[] args)
    {
        System.out.println("Program starts");

        try
        {
            System.out.println("Before method1 calling");
            method1();
            System.out.println("After method1 calling. Never will be shown");
        }
        catch (Exception e)
        {
           System.out.println("Exception has been caught");
        }
        System.out.println("Program is still running");
    }

    public static void method1()
    {
        int a = 100;
        int b = 0;
        System.out.println(a / b);
    }
}
Ось що буде виведено на екран:
"Program starts"
"Before method1 calling"
"Exception has been caught"
"Program is still running"
Не буде виведено «After method calling. Never will be shown »?! - У рядку 25 було ділення на нуль. Це призвело до виникнення помилки - виключення. Java-машина створила об'єкт ArithmeticException з інформацією про помилку. Цей об'єкт є винятком.

Усередині методу method1 виникло виключення. І це призвело до негайного завершення цього методу. Воно привело б і до завершення методу main, якби не було блоку try-catch.

Якщо всередині блоку try виникає виняток то, він захоплюється в блоці catch. Залишок коду в блоці try не буде виконаний, а відразу почнеться виконання блоку catch. Іншими словами цей код працює так:
  1. Якщо всередині блоку try виникло виключення, то код перестає виконуватися, і починає виконуватися блок catch.
  2. Якщо виняток не виник, то блок try виконується до кінця, а catch ніколи так і не почне виконуватися.
А що означає Exception всередині catch? - Всі виключення - це класи, успадковані від класу Exception. Ми можемо перехопити будь-яке з них, вказавши в блоці catch його клас, або все відразу, вказавши загальний батьківський клас - Exception. Потім з змінної e (ця змінна зберігає посилання на об'єкт виключення), можна отримати всю необхідну інформацію про виниклу помилку.

У Java всі винятки діляться на два типи - контрольовані (checked) і неконтрольовані (unchecked): ті, які перехоплювати обов'язково, і ті, які перехоплювати не обов'язково. За замовчуванням - всі виключення обов'язково потрібно перехоплювати.

У своєму коді ти сам можеш викидати виключення, навіть можеш написати свої власні виключення. 

Якщо в методі виникають виключення ClassNotFoundException і FileNotFoundException, програміст зобов'язаний вказати їх в сигнатурі методу (в заголовку методу). Це checked виключення.

Якщо в методі main хочеш викликати метод якогось об'єкта, в заголовку якого прописано throws FileNotFoundException, ... то треба зробити одне з двох:
  1. Перехоплювати виключення FileNotFoundException, ...Тоді доведеться вернути код виклику небезпечного методу в блок try-catch
  2. Чи не перехоплювати виключення FileNotFoundException, ...Тобі доведеться додати ці винятки в список throws свого методу main.
Спосіб 1: просто передаємо виняток вище:

public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException{
method1();
}
public static void method1() throws FileNotFoundException, ClassNotFoundException{
//тут виникне виключення FileNotFoundException, такого файлу немає
FileInputStream fis = new FileInputStream("C2:\\badFileName.txt");
}

А тут перехоплюємо його за допомогою try-catch:

Спосіб 2: перехоплення винятку:

public static void main(String[] args){
try{
method1();
}catch(Exception e){
}
}

public static void method1() throws FileNotFoundException, ClassNotFoundException{
//тут виникне виключення FileNotFoundException, такого файлу немає
FileInputStream fis = new FileInputStream("C2:\\badFileName.txt");
}

Не обробляємо виключення - потрібно прокинути їх далі, тому, хто знає як

public static void method2() throws FileNotFoundException, ClassNotFoundException{
method1();
}


Обробляємо один виняток, інший - передаємо:

public static void method3() throws ClassNotFoundException{
try{
method1();
}catch (FileNotFoundException e)
{
System.out.println("FileNotFoundException has been caught.");
}
}

Перехоплюємо обидва - нічого не передаємо:

public static void method4(){
try{
method1();
}catch (FileNotFoundException e)
{
System.out.println("FileNotFoundException has been caught.");
}catch (ClassNotFoundException e)
{
System.out.println("ClassNotFoundException has been caught.");
}
}


Але є вид винятків - це RuntimeException і класи, успадковані від нього. Їх перехоплювати не обов'язково. Це unchecked виключення. Вважається, що це важко прогнозовані виключення і передбачити їх появу практично неможливо. З ними можна робити все те ж саме, але вказувати в throws їх не потрібно.

Завдання 1.

Є метод, який викидає два винятки, успадковані від Exception, і два успадкованих від RuntimeException: NullPointerException, ArithmeticException, FileNotFoundException, URISyntaxException.  Потрібно перехопити NullPointerException і FileNotFoundException, але не перехоплювати ArithmeticException і URISyntaxException


import java.io.FileNotFoundException;
import java.net.URISyntaxException;
import java.util.HashMap;

public class Solution
{
public static void main(String[] args)  
{

//напишіть тут код

method1();

//
напишіть тут код

}

public static void method1() //напишіть тут код
{
int i = (int) (Math.random() * 4);
if (i == 0)
throw new   
//напишіть тут код    ;
if (i == 1)
throw new   
//напишіть тут код    ;
if (i == 2)
throw new   
//напишіть тут код    ;
if (i == 3)
throw new   
//напишіть тут код    ;
}
}

Завдання 2. Перехоплення checked винятків

У методі processExceptions обробіть всі checked виключення. Потрібно вивести на екран кожен checked виняток. Можна використовувати тільки один блок try.

import java.io.IOException;
import java.rmi.RemoteException;
public class Solution {
public static void main(String[] args) {
processExceptions(new Solution());
}
public static void processExceptions(Solution obj) {
//напишіть тут код
obj.method1();
obj.method2();
obj.method3();

}

public void method1() 
//напишіть тут код{
//напишіть тут код
}

public void method2()  
//напишіть тут код{
//напишіть тут код
}

public void method3()  
//напишіть тут код{
//напишіть тут код
}
}

Завдання 3. Перехоплення unchecked винятків 

У методі processExceptions обробіть всі unchecked  виключення. Потрібно вивести стек-трейс кожного виключення, використовуючи метод printStackМожна використовувати тільки один блок try.

public class Solution
{
public static void main(String[] args) {
processExceptions(new Solution());
}

public static void processExceptions(Solution obj) {
//напишіть тут код
obj.method1();
obj.method2();
obj.method3();
//напишіть тут код
}

public static void printStack(Throwable throwable) {
System.out.println(throwable);
//напишіть тут код
}

public void method1(){
//напишіть тут код
}

public void method2() {
//напишіть тут код
}

public void method3() {
//напишіть тут код
}
}
.