Stack trace

Java Syntax Pro
14 уровень , 5 лекция
Открыта

1. Получение стек-трейса

Получение стек-трейса

В языке программирования Java у программиста есть очень много способов получить информацию о том, что сейчас происходит в программе. И это не просто слова.

Например, программы на языке C++ после компиляции превращаются в один большой файл машинного кода и все, что во время выполнения доступно программисту, — это адрес куска памяти, который содержит машинный код, который сейчас выполняется. Не густо, скажем так.

В Java же, даже после компиляции, классы остаются классами, методы и переменные никуда не деваются, и у программиста есть много способов получить данные о том, что сейчас происходит в программе.

Стек-трейс

Например, в любой момент работы программы можно узнать класс и имя метода, который сейчас выполняется. И даже не одного метода, а получить информацию о всей цепочке вызовов методов от текущего метода до метода main().

Список, состоящий из текущего метода, метода, который его вызвал, его вызвавшего метода и т.д., называется stack trace. Получить его можно с помощью команды:

StackTraceElement[] methods = Thread.currentThread().getStackTrace();

Можно записать ее и в две строки:

Thread current = Thread.currentThread();
StackTraceElement[] methods = current.getStackTrace();

Статический метод currentThread() класса Thread возвращает ссылку на объект типа Thread, который содержит информацию о текущей нити (о текущем потоке выполнения). Подробнее о нитях вы узнаете в квесте Java Core.

У этого объекта Thread есть метод getStackTrace(), который возвращает массив элементов StackTraceElement, каждый из которых содержит информацию об одном методе. Все элементы вместе и образуют stack trace.

Пример:

Код
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(var info: methods)
         System.out.println(info);
   }
}
Вывод на экран
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)

Как мы видим по выводу на экран, в приведенном примере метод getStackTrace() вернул массив из трех элементов:

  • Метод getStackTrace() класса Thread
  • Метод test() класса Main
  • Метод main() класса Main

Из этого стек-трейса можно сделать вывод, что:

  • Метод Thread.getStackTrace() был вызван методом Main.test() в строке 11 файла Main.java
  • Метод Main.test() был вызван методом Main.main() в строке 5 файла Main.java
  • Метод Main.main() никто не вызывал — это первый метод в цепочке вызовов.

Кстати, на экране отобразилась только часть всей имеющийся информации. Все остальное можно получить прямо из объекта StackTraceElement



2. StackTraceElement

Класс StackTraceElement, как следует из его названия, создан для того, чтобы хранить информацию по одному элементу stack trace — т.е. по одному методу из StackTrace.

У объектов этого класса есть такие методы:

Метод Описание
String getClassName()
Возвращает имя класса
String getMethodName()
Возвращает имя метода
String getFileName()
Возвращает имя файла (в одном файле может быть много классов)
int getLineNumber()
Возвращает номер строки в файле, в которой был вызов метода
String getModuleName()
Возвращает имя модуля (может быть null)
String getModuleVersion()
Возвращает версию модуля (может быть null)

С их помощью можно получить более полную информацию о текущем стеке вызовов:

Код Вывод на экран Примечание
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(StackTraceElement info: methods)
      {
         System.out.println(info.getClassName());
         System.out.println(info.getMethodName());

         System.out.println(info.getFileName());
         System.out.println(info.getLineNumber());

         System.out.println(info.getModuleName());
         System.out.println(info.getModuleVersion());
         System.out.println();
      }
   }
}
java.lang.Thread
getStackTrace
Thread.java
1606
java.base
11.0.2

Main
test
Main.java
11
null
null

Main
main
Main.java
5
null
null
имя класса
имя метода
имя файла
номер строки
имя модуля
версия модуля

имя класса
имя метода
имя файла
номер строки
имя модуля
версия модуля

имя класса
имя метода
имя файла
номер строки
имя модуля
версия модуля


3. Стек

Что такое Stack Trace вы уже знаете, а что же такое сам Stack (Стек)?

Стек — это структура хранения данных, в которую можно добавлять элементы и из которой можно забирать элементы. Причем брать элементы можно только с конца: сначала последний добавленный, потом — предпоследний, и т.д.

Само название Stack переводится с английского как «стопка» и очень похоже на стопку бумаги. Если вы положите на стопку бумаги листы 1, 2 и 3, взять вы их сможете только в обратном порядке: сначала третий, затем второй, а только затем первый.

В Java даже есть специальная коллекция с таким поведением и таким же названием — Stack. Этот класс в своем поведении очень похож на ArrayList и LinkedList.  Однако у него есть еще методы, которые реализуют поведение стека:

Методы Описание
T push(T obj)
Добавляет элемент obj в конец списка (наверх стопки)
T pop()
Забирает элемент с верха стопки (высота стопки уменьшается)
T peek()
Возвращает элемент с верха стопки (стопка не меняется)
boolean empty()
Проверяет, не пуста ли коллекция
int search(Object obj)
Ищет объект из коллекции, возвращает его index

Пример:

Код Содержимое стека (вершина справа)
Stack<Integer> stack = new Stack<Integer>();
stack.push(1);
stack.push(2);
stack.push(3);
int x = stack.pop();
stack.push(4);
int y = stack.peek();
stack.pop();
stack.pop();

[1]
[1, 2]
[1, 2, 3]
[1, 2]
[1, 2, 4]
[1, 2, 4]
[1, 2]
[1]

Стек используется в программировании довольно часто. Так что это полезная коллекция.



4. Вывод стек-трейса при обработке ошибок

Почему же список вызовов методов назвали StackTrace? Да потому, что если представить список методов в виде стопки листов с именами методов, при вызове очередного метода на эту стопку кладется лист с именем метода, на него — следующий, и т.д.

Когда метод завершается, лист с верха стопки удаляется. Нельзя удалить лист из середины стопки, не удалив все листы, лежащие в нем — нельзя прекратить работу метода в цепочке вызовов, не завершив все методы, вызванные им.

Исключения

Еще одно интересное применение стека — обработка исключений.

Когда в программе происходит ошибка и создается исключение, в него записывается текущий stack trace: массив, состоящий из списка методов начиная с метода main и заканчивая методом, где произошла ошибка. Там даже есть строка, в которой было создано исключение!

Этот stack trace ошибки хранится внутри исключения и может быть легко извлечен из нее с помощью метода: StackTraceElement[] getStackTrace()

Пример:

Код Примечание
try
{
   // тут может возникнуть исключение
}
catch(Exception e)
{
   StackTraceElement[] methods = e.getStackTrace()
}




Захватываем исключение

Получаем из него стек-трейс в момент возникновения ошибки.

Это метод класса Throwable, а значит, все его классы-наследники (т.е. вообще все исключения), имеют метод getStackTrace(). Очень удобно, не так ли?

Печать стек-трейса ошибки

Кстати, у класса Throwable есть еще один метод для работы со stack-trace: он выводит в консоль всю информацию по stack trace, который хранится внутри исключения. Он так и называется printStackTrace().

Вызвать его можно у любого исключения, что очень удобно.

Пример:

Код
try
{
   // тут может возникнуть исключение
}
catch(Exception e)
{
   e.printStackTrace();
}
Вывод на экран
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)


Комментарии (249)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
I'll kick them all Уровень 5
27 июля 2025
Какой-то древний JDK=). У списка даже нет методов getFirst(), addFirst(). Так и пойми почему не принимает сервер. Всю статистику запорол.
Никита Уровень 1
25 июля 2025
Задачу "стек в домашних условиях" решил просто, заменив:

private final List<String> storage = new LinkedList<>();
на:

private final LinkedList<String> storage = new LinkedList<>();
А у класса LinkedList все необходимые методы уже реализованы. Возможно, если создатели задачи предполагали, что нам нужно самостоятельно переписать методы push(), pop() и остальные, то лучше добавить условие в требованиях к задаче, что тип переменной storage менять запрещено. А то я не понял этого сразу :)
Anonymous #3585174 Уровень 33
10 июля 2025
like
Сергей Уровень 26
10 июля 2025
В примечание к последней задаче не мешало бы добавить фразу: ЕСЛИ ВСЕ БУДЕТ ГОРЕТЬ КРАСНЫМ, НЕ ПУГАЙТЕСЬ, эТо НоРмАлЬнО! Так держать! Ахах
Виктор Уровень 23
8 июля 2025
Потупил с printf, но не долго).
Ivan Уровень 16
7 июля 2025
прикольные задачки. методы LinkedList пришлось искать в прошлых лекциях, даже попробовал изменить List на Deque, чтобы заработали методы addFirst(), peekFirst() и т.д. но она решается и без этого, оказалось все намного проще. хоть и последний метод seach выполняется неправильно.
Riga Уровень 22
2 апреля 2025
Я правильно понимаю метод getStackTrace есть у классов Thread и Throwable?) первый получает инфу просто от работы программы а второй о исключениях…
Хэйли Эванс Уровень 19
31 марта 2025
а что за прикол с последней задачей? решение верное но вывода нет как такового, выдает ошибку при запуске но проверку проходит, мой перфекционист негодует
Konstantin Уровень 115
10 апреля 2025
Ты же стектрэйс выводишь, это информация о состоянии программы, включая ошибку
Rasul Shidakov Уровень 20
31 марта 2025
интересно, для чего объяснять сначала про стеки (3 блок), описывать его методы и тд, а затем давать задачу на другую коллекцию... больше тренировка внимательности чем навыков программирования...
ozmeow Уровень 1
14 мая 2025
привыкай)
Victor Уровень 38
30 января 2025
вывод на консоль должен быть такой [4, 3, 2, 1, 0] [3, 2, 1, 0] 3 false 0 -1