— Привет, Амиго! Сегодня будет очень интересный урок. Сегодня я расскажу тебе об исключениях. Исключения – это специальный механизм для контроля над ошибками в программе. Вот примеры ошибок, которые могут возникнуть в программе:
1. Программа пытается записать файл на заполненный диск.
2. Программа пытается вызвать метод у переменной, которая хранит ссылку – null.
3. Программа пытается разделить число на 0.
Все эти действия приводят к возникновению ошибки. Обычно это приводит к закрытию программы — продолжать выполнять дальше код не имеет смысла.
— Почему?
— А есть ли смысл крутить руль, если машина слетела с трассы и падает с обрыва?
— Программа что, должна завершиться?
— Да. Раньше так и было. Любая ошибка приводила к завершению программы.
— Это очень разумный подход.
— А разве не лучше было бы попробовать работать дальше?
— Ага. Ты набрал большущий текст в Word’е, сохранил его, он не сохранился, но программа говорит тебе, что все в порядке. И ты продолжаешь набирать его дальше. Глупо, да?
— Ага.
— Потом разработчики придумали интересный ход: каждая функция возвращала статус своей работы. 0 означал, что она отработала как надо, любое другое значение – что произошла ошибка: это самое значение и было кодом ошибки.
— Но был у такого подхода и минус. После каждого(!) вызова функции нужно было проверять код (число), который она вернула. Во-первых, это было неудобно: код по обработке ошибок исполнялся редко, но писать его нужно было всегда. Во-вторых, функции часто сами возвращают различные значения – что делать с ними?
— Ага. Я тоже об этом подумал.
— Но потом наступило светлое будущее — появились исключения и механизм обработки ошибок. Вот как это работает:
1. Когда возникает ошибка, Java-машина создаёт специальный объект – exception – исключение, в который записывается вся информация об ошибке. Для разных ошибок есть разные исключения.
2. Затем это «исключение» приводит к тому, что программа тут же выходит из текущей функции, затем выходит из следующей функции, и так пока не выйдет из метода main. Затем программа завершается. Еще говорят, что Java-машина «раскручивает назад стек вызовов».
— Но ты же сказала, что теперь программа не обязательно завершается.
— Верно, потому что есть способ перехватить исключение. В нужном месте, для нужных нам исключений мы можем написать специальный код, который будет перехватывать эти исключения и что-то делать. Важное.
— Для этого есть специальная конструкция try-catch. Вот как это работает:
Вот пример программы, которая перехватывает исключение – деление на 0. И продолжает работать. |
---|
|
Вот что будет выведено на экран: |
|
— А почему не будет выведено «After method1 calling. Never will be shown»?
— Рада, что ты спросил. В строчке 25 у нас было деление на ноль. Это привело к возникновению ошибки – исключения. Java-машина создала объект ArithmeticException с информацией об ошибке. Этот объект является исключением.
— Внутри метода method1
возникло исключение. И это привело к немедленному завершению этого метода. Оно привело бы и к завершению метода main, если бы не было блока try-catch.
— Если внутри блока try возникает исключение то, оно захватывается в блоке catch. Остаток кода в блоке try, не будет исполнен, а сразу начнётся исполнение блока catch.
— Как-то не очень понятно.
— Другими словами этот код работает так:
1. Если внутри блока try возникло исключение, то код перестаёт исполняться, и начинает исполняться блок catch.
2. Если исключение не возникло, то блок try исполняется до конца, а catch никогда так и не начнёт исполняться.
— Гм?
— Представь, что после вызова каждого метода мы проверяем: завершился ли только что вызванный метод сам по себе или в результате исключения. Если исключение было, тогда мы переходим на исполнение блока catch, если он есть, и захватываем исключение. Если блока catch нет, то завершаем и текущий метод. Тогда такая же проверка начинается в том методе, который вызвал нас.
— Теперь вроде понятно.
— Вот и отлично.
— А что значит Exception внутри catch?
— Все исключения – это классы, унаследованные от класса Exception. Мы можем перехватить любое из них, указав в блоке catch его класс, или все сразу, указав общий родительский класс — Exception. Затем из переменной e (эта переменная хранит ссылку на объект исключения), можно получить всю необходимую информацию о возникшей ошибке.
— Круто! А если в моем методе могут возникнуть разные исключения, можно обрабатывать их по-разному?
— Не можно, а нужно. Сделать это можно вот так:
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 (NullPointerException e)
{
System.out.println("Reference is null. Exception has been caught");
}
catch (ArithmeticException e)
{
System.out.println("Division by zero. Exception has been caught");
}
catch (Exception e)
{
System.out.println("Any other errors. 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);
}
}
— Блок try может содержать несколько блоков catch, каждый из которых будет захватывать исключения своего типа.
— Гм. Ну, вроде понятно. Сам такого не напишу, конечно, но если в коде встречу – пугаться не буду.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ