Help me figure out the StackTraceElement[]


Good time of day. Help us understand the essence of StackTrace.

The training material provides an explanation of

The Java machine records all function calls. She has a special collection for this-a stack. When one function calls another, the Java machine puts a new StackTraceElement on this stack. When the function terminates, this element is removed from the stack. Thus, this stack always stores up-to-date information about the current state "function call stack"

The following is an example of

 public static void main(String[] args)
  {
    method1();
  }

  public static void method1()
  {
    method2();
  }

  public static void method2()
  {
    method3();
  }

  public static void method3()
  {
    StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
    for (StackTraceElement element : stackTraceElements)
    {
       System.out.println(element.getMethodName());
    }
  }

As a result of which we get

getStackTrace
method3
method2
method1
main

If I understand everything correctly, then the construction

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

It works as follows:

//Cоздаём переменную типа StackTraceElement[]
StackTraceElement[] stackTraceElements 

//Присваеваем ей ссылку на текущий поток и заносим в массив специальные элементы StackTrace
Thread.currentThread().getStackTrace()

Question #1: how does this array StackTraceElement[] contain all the information about the called methods, if it says that after the method is executed, the information is removed from the stack?

Question #2: In one of the tasks, you are asked to return the name of the method that uses it calls

 public static void main(String[] args) throws Exception
{
    method1();
}

public static String method1()
{
    method2();
    return Thread.currentThread().getStackTrace()[2].getMethodName();


}

public static String method2()
{
    method3();
    return Thread.currentThread().getStackTrace()[2].getMethodName();
}

public static String method3()
{
    method4();
    return Thread.currentThread().getStackTrace()[2].getMethodName();
}

public static String method4()
{
    method5();
    return Thread.currentThread().getStackTrace()[2].getMethodName();
}

public static String method5()
{
    return Thread.currentThread().getStackTrace()[2].getMethodName();
}

How does the {[9] construction work?]}

return Thread.currentThread().getStackTrace()[2].getMethodName();

If we didn't create StackTraceElement[]. Does this mean that it is implicitly created by the JVM when the program is executed?

Author: post_zeew, 2016-12-12

3 answers

Question #1: how does this array StackTraceElement[] contain all the information about the called methods, if it says that after the method is executed, the information is removed from the stack?

You call the getStackTrace() method in the method3() method. At the time of calling getStackTrace(), the method3() method has not yet completed, therefore, the getStackTrace() method will return the entire call chain up to the getStackTrace() method call.

If, for example, you call getStackTrace() in the method main(...) after calling the method1() method, then get the following output:

getStackTrace
main

You don't see the method1() and other methods here – the records of their calls were deleted, because at the time of calling the getStackTrace() method, the method1() was completed.

Question #2: In one of the tasks, you are asked to return the name of the method that calls it

...

How does the construction

return Thread.currentThread().getStackTrace()[2].getMethodName();

If we didn't create a StackTraceElement[]. Does this mean that it is implicitly created by the JVM when executed programs?

Yes, then. The JVM itself adds elements to the call stack.

At the top of the stack is a record of the call to the getStackTrace() method itself, followed by a record of the name of the method directly in which the getStackTrace() method was called, in the element getStackTrace()[i] (i>0) is the name of the method that called the method, which is in getStackTrace()[i-1].

 5
Author: post_zeew, 2016-12-12 17:58:46

It's just not clear why you're returning the [2] element. In your task, you need to return the name of the method that calls it.

public static String method5() {
    return Thread.currentThread().getStackTrace()**[2]**.getMethodName(); }

In this case, it will be called by the current method 5. The stack length can be checked by calling the length method: Thread.currentThread().getStackTrace().length - the number of methods written to the Stack, in this case there will be 7 entries. The last element will be the getStacktrace() method itself. We need to return the method that calls it, so we need to return i-1-1(5) (the numbering of elements in the java array starts with the index '0'). as a result, we get:

return Thread.currentThread().getStackTrace()[5].getMethodName();

For method 4, it will be

return Thread.currentThread().getStackTrace()[4].getMethodName();

But if you want to output the line number that called this method, then yes, return Thread.currentThread().getStackTrace()[1].getLineNumber() returns the line number of method 4 that called method 5.

 2
Author: Константин Соловьев, 2020-08-14 07:00:56

The answer above is a bit inaccurate. In the stack, the method that called StackTrace will always be at position[2].

  • 0 - getStackTrace

  • 1 - method name (your own name)

  • 2 - method name who called it[1]

  • 3 - method name who called it[2]

  • 4 - etc.

Here we see the past, what happened before the current method was launched.

 1
Author: lex, 2018-02-06 00:06:39