Виртуальная Машина Java (в дальнейшем JVM) обрабатывая код, запускает методы один за другим, начиная с метода
main
. Когда она доходит до очередного метода, говорится, что этот метод находится на вершине стека. После полного выполнения метода, он удаляется из стека, и сменяется следующим в очереди. Для демонстрации принципа, наберите данный код:
package errorhandling;
public class errorChecking {
public static void main(String[] args) {
System.out.println("Метод Main успешно запущен");
m1();
System.out.println("Метод Main заканчивает свою работу");
}
static void m1() {
System.out.println("Первый метод передаёт привет!(m1)");
m2();
}
static void m2() {
System.out.println("Второй метод передаёт привет(m2)");
}
}
У нас три метода: метод main
, метод m1
и метод m2
. Когда программа стартует, на вершине стека расположен метод main
. Внутри метода main
, вызывается метод m1
. Вызываясь, он прыгает на верхушку стека. Метод m1
в свою очередь вызывает метод m2
. Теперь уже метод m2
, прыгает на верхушку стека, временно отстраняя m1
. На секунду представьте это — main
, сверху m1
и на вершине m2
! Сделав свои дела, m2
завершается, и контроль возвращается обратно к m1
. Метод m1
, завершаясь, тоже удаляется из стека, и управление вновь получает метод main
.
Запустите вашу программу и посмотрите на окно вывода:
Метод Main успешно запущен
Первый метод передаёт привет!(m1)
Второй метод передаёт привет(m2)
Метод Main заканчивает свою работу
Если что-то пойдёт не так в методе m2
, JVM (Виртуальная Машина Джава, вы помните, да?) будет искать обработчиков ошибок, например блок try … catch
. Если в методе m1
обработчика ошибок нет, то исключение будет передано методу m1
, в надежде, что он сумеет её обработать. Если и здесь не обнаружит обработчика ошибок,то исключение снова перейдёт по стеку вверх, на этот раз в метод main
. Если метод main
не взаимодействует с исключением, вы получите странное сообщение об ошибке, напечатанное в окне вывода. В качестве примера, приведите ваш метод m2
к следующему виду:
static void m2() {
int x = 10;
int y = 0;
double z = x / y;
System.out.println( z );
System.out.println("Method Two - m2");
}
Этот метод содержит ошибку деления на ноль.
А вот полный вариант программы, сверьтесь со своим:
package errorhandling;
public class errorChecking {
public static void main(String[] args) {
System.out.println("Метод Main успешно запущен");
m1();
System.out.println("Метод Main заканчивает свою работу");
}
static void m1() {
System.out.println("Первый метод передаёт привет!(m1)");
m2();
}
static void m2() {
int x = 10;
int y = 0;
double z = x / y;
System.out.println( z );
System.out.println("Method Two - m2");
}
}
Запустите программу и посмотрите, что выдаст вам окно вывода:
Метод Main успешно запущен
Первый метод передаёт привет!(m1)
Exception in thread "main" java.lang.ArithmeticException: / by zero
at errorhandling.errorChecking.m2(<u>errorChecking.java:17</u>)
at errorhandling.errorChecking.m1(<u>Solution.java:11</u>)
at errorhandling.errorChecking.main(<u>>Solution.java:5</u>)
Process finished with exit code 1
Вы смотрите на нечто, называемое стек-трейс. Три строки, подчёркнутые голубым, ссылаются на ваши методы, и могут быть найдены в:
имя_пакета.имя_класса.имя_метода
Первая сверху строка — это место, где ошибка возникла — в методе m2
. Java проследила, что бы она была обработана ArithmeticException
, которая вылавливает ошибки деления на ноль. В методах m2
, m1
и main
нет обработчика ошибок. Так что программа обработала её обработчиком ошибок по-умолчанию.
Измените ваш метод m1
на следующий:
try {
System.out.println("Первый метод передаёт привет!(m1)");
m2( );
}
catch (ArithmeticException err) {
System.out.println(err.getMessage());
}
Теперь мы обернули метод m2
в блок try
. В части catch
, мы используем тип исключения, что был выявлен в стек-трейсе — ArithmeticException
.
Запустите код снова, и в окне вывода увидите следующее:
Метод Main успешно запущен
Первый метод передаёт привет!(m1)
/ by zero
Метод Main заканчивает свою работу
Заметьте, что сообщение об ошибке вывелось как: "/ by zero". Метод m2
не был выполнен полностью, а был остановлен, когда возникла ошибка. Затем контроль был передан обратно m1
. Это произошло благодаря тому, что блок catch
сам распознавал ошибку, JVM не стала обращаться к стандартному обработчику ошибок, а вывела сообщение находящееся между фигурными скобками блока catch
.
Обратите внимание, что сама программа не была остановлена. Контроль, как обычно перешёл к методу main
, откуда m1
был вызван. И последняя строка метода main
, таки смогла вывести на экран "End Main method". Это имеет очень-очень важное значение. Если бы вам нужно было значение из m1
, для последующей работы где-то в main
. И если значения там не окажется, то ваша программа может отработать совсем не так, как вы ожидаете.
Когда вы увидите стек-трейс в окне вывода, просто знайте, что первая строка — это то место, где проблема возникла, а остальные строки (если конечно они есть), куда исключение было передано вверх по стеку, обычно заканчивая методом main
.
Перевод с сайта homeandlearn.co.uk
Говорим спасибо: Серегею Сысоеву, Treefeed...
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ