Java Language
API de apilación
Buscar..
Introducción
Antes de Java 9, el acceso a los marcos de la pila de hilos estaba limitado a una clase interna sun.reflect.Reflection
. Específicamente el método sun.reflect.Reflection::getCallerClass
. Algunas bibliotecas se basan en este método que está en desuso.
Una API estándar alternativo ahora se proporciona en el JDK 9 a través de la java.lang.StackWalker
clase, y está diseñado para ser eficiente al permitir el acceso perezoso para los marcos de pila. Algunas aplicaciones pueden usar esta API para atravesar la pila de ejecución y filtrar en las clases.
Imprimir todos los marcos de pila de la secuencia actual
Lo siguiente imprime todos los marcos de pila del hilo actual:
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 }
Salida:
test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main
Imprimir la clase de llamada actual
A continuación se imprime la clase de llamada actual. Tenga en cuenta que, en este caso, StackWalker
debe crearse con la opción RETAIN_CLASS_REFERENCE
, para que Class
instancias de la Class
se conserven en los objetos StackFrame
. De lo contrario se produciría una excepción.
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());
}
}
Salida:
class test.FooHelper
Mostrando la reflexión y otros marcos ocultos.
Un par de otras opciones permiten que los seguimientos de pila incluyan marcos de implementación y / o reflexión. Esto puede ser útil para propósitos de depuración. Por ejemplo, podemos agregar la opción SHOW_REFLECT_FRAMES
a la instancia de StackWalker
momento de la creación, para que también se impriman los marcos para los métodos reflectivos:
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());
}
}
}
Salida:
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
Tenga en cuenta que los números de línea para algunos métodos de reflexión pueden no estar disponibles, por lo que StackFrame.getLineNumber()
puede devolver valores negativos.