
— И ещё немного интересных уроков. Мне так нравится преподавать.
— Хочу рассказать тебе, как работает множественный catch. Все очень просто: при возникновении исключения в блоке try, выполнение программы передаётся на первый catch.
— Если тип, указанный внутри круглых скобок блока catch, совпадает с типом объекта-исключения, то начинается выполнение кода внутри блока {}. Иначе переходим к следующему catch. Там проверка повторяется.
— Если блоки catch закончились, а исключение так и не было перехвачено, то оно выбрасывается дальше, а текущий метод аварийно завершается.
— Ясно. Будет выполнен тот catch, тип в котором совпадает с типом исключения.
— Да, верно. Но в реальности все немного сложнее. Дело в том, что классы можно наследовать друг от друга. И если класс «Корова» унаследовать от класса «Животное», то объект типа «Корова» можно хранить не только в переменной типа «Корова», но и в переменной типа «Животное».
— И?
— Т.к. все исключения унаследованы от классов Exception или RuntimeException (который тоже унаследован от Exception), то их все можно перехватить командами catch (Exception e) или catch (RuntimeException e).
— И?
— Отсюда два вывода. Во-первых, с помощью команды catch(Exception e) можно перехватить любое исключение вообще. Во-вторых — порядок блоков catch имеет значение.
Примеры:
— Возникший при делении на 0 ArithmeticException
будет перехвачен во втором catch.
try
{
System.out.println("Before method1 calling.");
int a = 1 / 0;
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.");
}
— В примере ниже возникший ArithmeticException
будет перехвачен в первом catch, т.к. классы всех исключений унаследованы от Exception. Т.е. Exception
захватывает любое исключение.
try
{
System.out.println("Before method1 calling.");
int a = 1/0;
System.out.println("After method1 calling. Never will be shown.");
}
catch (Exception e)
{
System.out.println("Any other errors. Exception has been caught.");
}
catch (NullPointerException e)
{
System.out.println("Reference is null. Exception has been caught.");
}
catch (ArithmeticException e)
{
System.out.println("Divided by zero. Exception has been caught.");
}
— В примере ниже исключение ArithmeticException
не будет перехвачено, а будет выброшено дальше в вызывающий метод.
try
{
System.out.println("Before method1 calling.");
int a = 1/0;
System.out.println("After method1 calling. Never will be shown.");
}
catch (NullPointerException e)
{
System.out.println("Reference is null. Exception has been caught.");
}
— Ну, вроде все понемногу проясняется. Непростая штука эти исключения.
— Это только кажется так. На самом деле – это чуть ли не самая простая вещь в Java.
— Не знаю, радоваться по этому поводу или огорчаться…
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
гештальтыкаждый метод по очереди. Четвертый, третий, второй, первый и наконец вы возвращаетесь в main - это страница с которой всё началось (портал mail.ru). Вы выдыхаете и закрываете браузер. Всё, ваша программа завершилась. Вот примерно так работает стек вызовов. И если например в 6-м методе вы увидели нечто такое, что выбило вас из колеи и метод завершается аварийно, процесс возврата всё равно пройдет по всему стеку в самый низ, до метода main (чтобы собрать полный стек вызовов и вывести StackTrace в консоль). Так вот, чтобы такого не случилось, и программа не вылетала обратно на mail.ru с потерей всех данных, мы и перехватываем исключение прямо в том методе в котором оно возникло. В итоге программа аварийно вылетит только из одного метода и спокойно продолжит работать со следующей строчки кода после той где был вызван этот "плохой" метод.