Поиск…


Вступление

До Java 9 доступ к кадрам стека потоков был ограничен внутренним классом sun.reflect.Reflection . В частности, метод sun.reflect.Reflection::getCallerClass . Некоторые библиотеки полагаются на этот метод, который устарел.

Альтернативный стандарт API , теперь предоставляется в JDK 9 через java.lang.StackWalker класса, и предназначен , чтобы быть эффективными, позволяя ленивый доступ к кадрам стеки. Некоторые приложения могут использовать этот API для прохождения стека выполнения и фильтрации по классам.

Печать всех кадров стека текущего потока

Следующее выводит все кадры стека текущего потока:

1  package test;
2  
3  import java.lang.StackWalker.StackFrame;
4  import java.lang.reflect.InvocationTargetException;
5  import java.lang.reflect.Method;
6  import java.util.List;
7  import java.util.stream.Collectors;
8  
9  public class StackWalkerExample {
10 
11    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
12        Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
13        fooMethod.invoke(null, (Object[]) null);
14    }
15 }
16
17 class FooHelper {
18    protected static void foo() {
19        BarHelper.bar();
20    }
21 }
22 
23 class BarHelper {
24    protected static void bar() {
25        List<StackFrame> stack = StackWalker.getInstance()
26                .walk((s) -> s.collect(Collectors.toList()));
27        for(StackFrame frame : stack) {
28            System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName());
29        }
30    }
31 }

Выход:

test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main

Распечатать текущий класс вызывающего абонента

Следующее выводит текущий класс вызывающего абонента. Обратите внимание, что в этом случае StackWalker необходимо создать с помощью опции RETAIN_CLASS_REFERENCE , чтобы экземпляры Class сохранялись в объектах StackFrame . В противном случае произойдет исключение.

public class StackWalkerExample {

    public static void main(String[] args) {
        FooHelper.foo();
    }

}

class FooHelper {
    protected static void foo() {
        BarHelper.bar();
    }
}

class BarHelper {
    protected static void bar() {
        System.out.println(StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).getCallerClass());
    }
}

Выход:

class test.FooHelper

Отображение отражения и других скрытых фреймов

Пара других опций позволяет трассировать трассировки стека реализации и / или отражения. Это может быть полезно для целей отладки. Например, мы можем добавить параметр SHOW_REFLECT_FRAMES к экземпляру StackWalker при создании, чтобы также были напечатаны кадры для отражающих методов:

package test;

import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

public class StackWalkerExample {

    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
        fooMethod.invoke(null, (Object[]) null);
    }
}

class FooHelper {
    protected static void foo() {
        BarHelper.bar();
    }
}

class BarHelper {
    protected static void bar() {
        // show reflection methods
        List<StackFrame> stack = StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES)
                .walk((s) -> s.collect(Collectors.toList()));
        for(StackFrame frame : stack) {
            System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName());
        }
    }
}

Выход:

test.BarHelper 27 bar
test.FooHelper 20 foo
jdk.internal.reflect.NativeMethodAccessorImpl -2 invoke0
jdk.internal.reflect.NativeMethodAccessorImpl 62 invoke
jdk.internal.reflect.DelegatingMethodAccessorImpl 43 invoke
java.lang.reflect.Method 563 invoke
test.StackWalkerExample 14 main

Обратите внимание, что номера строк для некоторых методов отражения могут быть недоступны, поэтому StackFrame.getLineNumber() может возвращать отрицательные значения.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow