Java Language
Stack-Walking API
サーチ…
前書き
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