In this article, you will learn and understand how the Java phenomenon StackTrace, also known as Call Stack Tracing, works. This information has been structured for beginners who encountered this concept at the beginning of Java Syntax Level 9. I think all of you, at least once, have encountered similar errors when working in your IDE, regardless of whether it was Idea , Eclipse or something else.
Exception in thread "main" java.lang.ArithmeticException
at com.example.task01.Test.division(Test.java:10)
at com.example.task01.Test.main(Test.java:6)
This, as you may have guessed, is our tracing. But don’t rush to panic, now we’ll break this example down for you. First you need to understand the fact that it StackTrace
works as Стэк
its name suggests. At this point we will dwell in a little more detail. At the eighth level, you have already become acquainted with collections and know that they are divided into three groups Set
- set, List
- list, Map
- dictionary (or map). According to JavaRush (c). Ours Stack
is part of the group List
. The principle of its operation can be described as LIFO , which stands for Last In First Out. Namely, this is a list similar to a stack of books; in order to take the element that we put in Stack
first, we need to first extract all the elements that we added to our list after. As indicated in the picture above, unlike, for example, a regular list ArrayList
where we can get any element from the list by index. Once again for reinforcement. Getting an element from Стэка
is only possible from the end! While the first element added to it is at the beginning (or at the bottom, as is more convenient). These are the methods our Stack
Object has push()
- Adds an element to the top of the stack. Object pop()
- Returns the element at the top of the stack, removing it in the process. Object peek()
- Returns the element at the top of the stack, but does not remove it. int search()
- Searches for an element on the stack. If found, its offset from the top of the stack is returned. Otherwise -1 is returned. boolean empty()
- Checks if the stack is empty. Returns true if the stack is empty. Returns false if the stack contains elements. So why do you Java
need StackTrace
one built on the principles of operation Stack
? Let's look at the example of an error below that occurred during the execution of such a simple program.
public class Test {
public static void main(String[] args) {
System.out.println(convertStringToInt(null));
}
public static int convertStringToInt(String s) {
int x = Integer.parseInt(s);
return x;
}
}
We have a class Test
with two methods. Everyone is familiar main
and convertStringToInt
the logic of which is to convert and return a string received from the outside (namely from the method main
) into an integer number of type int
. As you can see, we intentionally passed the parameter instead of a string with some number null
. Our method could not process this parameter correctly and caused an error NumberFormatException
. As you know, the program begins to work out its work from the method main
and at this moment it creates a new Стэк
one with a name StackTrace
where it puts the current value of its work under number 1 , then we go to the method convertStringToInt
and the program again enters the parameters of our location into the one created earlier StackTrace
under number 2 , then it is called a method invisible to our eyes parseInt
located in the class Integer
and this will already be element number 3 of ours StackTrace
, in this method there will be another internal call added to StackTrace
number 4 to check the element for null which will lead to an error. The program needs to display our error indicating the entire chain of our transitions until the error occurred. This is where the one previously created with the data of our transitions comes to her aid StackTrace
.
Exception in thread "main" java.lang.NumberFormatException: null
at java.base/java.lang.Integer.parseInt(Integer.java:614)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at com.example.task01.Test.convertStringToInt(Solution.java:10)
at com.example.task01.Test.main(Solution.java:6)
Before the error occurred, the program went deep into the methods, but as soon as the error occurred, everything begins to happen in the reverse order. A line describing the problem is printed (No. 1 in the example), then the last (and at the top) value added to ours is taken, Стэк
it was number four and printed to the console (No. 2 in the example) and we see that the problem arose in the class Integer
at 614 line of code and called this line, line 770 of a method parseInt
of the same class (No. 3 in the example) which, when added to, Стэк
was number three and this class method, Integer
still not visible to us, was already called by our method convertStringToInt
located on line 10 of our program (No. 4 in the example, and when adding it was second), and it, in turn, was called main
on line 6 (No. 5 in the example, and when adding, respectively, the first). So, by storing Стек
our called methods step by step, we were able to return back to main
parallel printing of information that exactly led us to the error. But StackTrace
this is not only working with errors, it allows us to get a lot of interesting information about the process of our application. Let's look at another popular example in the comments to the main lecture of level 9. We have the code and I’ll immediately attach a picture to it that visualizes the process of the program:
public class Test {
public static void main(String[] args) {
method1();
method2();
}
public static void method1() {
//не вызывает ничего
}
public static void method2() {
method3();
method4();
}
public static void method3() {
//не вызывает ничего
}
public static void method4() {
method5();
}
public static void method5() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for (StackTraceElement element:stackTraceElements) {
System.out.println(element.getMethodName());
}
}
}
Here our program does its job flawlessly and ends. This is what we will see in the console output:
getStackTrace
method5
method4
method2
main
Process finished with exit code 0
How did we get this conclusion and what happened in the fifth method, starting from line 20? I'm afraid the best thing I can do is add the most popular explanation (abbreviated) by user Kirill from the comments to the lecture. Let's turn to the creation line StackTrace
and analyze it element by element:
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement[]
- an indication of the type of the array (At early levels you already learned about arrays like int[], String[], here it’s the same). stackTraceElements
- the name of the array can be anything, taking into account the general naming rules, this does not affect the work. Thread.currentThread()
- obtaining a link to the current thread in which the methods that we want to track are executed (for now this is not important, you will analyze threads in more detail at level 16 in the Java Core quest) getStackTrace()
- we get all Стэк
the called methods (This is a regular getter for StackTrace
) Now let's see what The created array may be useful to us. We understand that the array stores information about executed methods. (c) And for this, in the 21st line, we launch a modified cycle for
called forEach
(by the way, for those who have not yet studied this cycle, I advise you to read about it) and output data from the array to the console, namely information about which methods were executed during the work using the construction element.getMethodName()
. Attention, as we see, the zero element of the array turned out to be itself, getStackTrace()
respectively, since at the moment of receiving the data array it was the last method that was executed and thereby ended up at the top Стэка
, and remembering our construction “ Last in, first out ” is immediately the first to be added to the array under the zero element. Here's what else we can get from StackTraceElement
: String getClassName()
- Returns the name of the class. String getMethodName()
- Returns the name of the method. String getFileName()
- Returns the file name (there can be many classes in one file). String getModuleName()
- Returns the module name (can be null). String getModuleVersion()
- Returns the module version (can be null). int getLineNumber()
- Returns the line number in the file in which the method was called. Now that you understand the general principle of operation, I advise you to try different methods yourself StackTrace
in your Ide . Even if you haven’t completely mastered everything, continue learning and the puzzle will turn out the same way it turned out for me in this matter. I wish you all success! Ps If you liked this material, please support it with a like. It's not difficult for you, I'm pleased. Thanks and see you at level 41 ;)