JavaRush /Блог /Архив info.javarush /Стек-трейс Java
IvanDurov
25 уровень

Стек-трейс Java

Статья из группы Архив info.javarush
Виртуальная Машина Java (в дальнейшем JVM) обрабатывая код, запускает методы один за другим, начиная с метода main. Когда она доходит до очередного метода, говорится, что этот метод находится на вершине стека. После полного выполнения метода, он удаляется из стека, и сменяется следующим в очереди. Для демонстрации принципа, наберите данный код: Стек-трейс Java - 1

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...
Комментарии (12)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Artem Sokolov Уровень 26
29 июня 2022
Здесь похоже опечатка: "Если в методе m1 обработчика ошибок нет, то исключение будет передано методу m1, в надежде, что он сумеет её обработать. "
hidden #2595317 Уровень 45
26 мая 2021
Если в методе m1 обработчика ошибок нет, то исключение будет передано методу m1, в надежде, что он сумеет её обработать/ Исправьте м1 первый на м2.
🦔 Виктор Уровень 20 Expert
5 ноября 2020
Спасибо за перевод, доступна, легкая и понятная выжимка по стековому пути. Забираю в свой список статей по этой теме, не смотря на то, что перевод лежит в архиве от 2013 года. Можно на эту тему ещё почитать следующие статьи: Структуры данных — стек и очередь. Stack Trace и с чем его едят. p. s. Очень интересно, как работает редактирование статьи на ДжаваРаше, потому что очень много статей, вне лекций, написаны с банальными опечатками, дублями и висят в таком виде годами и на эти материалы ссылаются официальные лекции курса ( ! ). Не хочу быть занудой, но создаётся ощущение, что либо редактировать статьи после публикации нельзя, либо неужели авторам настолько безразлична дальнейшая судьба работы?..
Bogdan Уровень 19
21 июля 2020
public class errorChecking Имена классов и интерфейсов начинаются с большой буквы и пишутся в стиле CamelCase. Имена методов и переменных начинаются с маленькой буквы.
Гвазава Сергей Уровень 31
24 февраля 2020
Когда вы увидите стек-трейс в окне вывода, просто знайте, что первая строка — это то место, где проблема возникла, а остальные строки (если конечно они есть), куда исключение было передано вверх по стеку, обычно заканчивая методом main. (я могу ошибаться, но наверно вниз по стеку? если последующие методы кладутся сверху, то метод MAIN будет внизу стека)
namor Уровень 1
20 января 2020
"если в методе m1 обработчика ошибок нет, то исключение будет передано методу m1" и так и передавал он его сам себе 30 лет и три года....
Anonymous #2135740 Уровень 41
5 октября 2019
"Если в методе m1 обработчика ошибок нет, то исключение будет передано методу m1, в надежде, что он сумеет её обработать". Предполагаю, что допущена опечатка и первый метод нужно указать, как m2?
BariO Уровень 19
5 сентября 2019
спасибо за внесение еще большей ясности
Дмитрий Уровень 22
22 августа 2019
Я так понял: Стек это стек FIFO, получается при отработки try / catch JVM ищет нужное исключение так же в других методотах стека где в недрах JVM и только когда она нашла нужный она помещает вызов этого исключения на вершину стека с которым мы и работаем в отработку исключения.
hundr3th Уровень 33
14 марта 2015
Спасибо, но было бы еще удобнее, если метод1 работал бы как мэин, т.е. после выполнения метода2 выводилось бы сообщение, что метод1 завершил работу с: