1. 概述
有时我们需要知道当前正在执行的Java方法的名称,这篇文章介绍了几种在当前执行堆栈中获取方法名称的简单方法。
2.Java9:StackWalking API
Java 9引入了Stack-Walking API,以一种惰性且高效的方式遍历JVM堆栈帧。为了使用此API找到当前正在执行的方法,我们可以编写一个简单的测试:
class CurrentExecutingMethodUnitTest {
@Test
void givenJava9_whenWalkingTheStack_thenFindMethod() {
StackWalker walker = StackWalker.getInstance();
Optional<String> methodName = walker.walk(frames -> frames
.findFirst()
.map(StackWalker.StackFrame::getMethodName)
);
assertTrue(methodName.isPresent());
assertEquals("givenJava9_whenWalkingTheStack_thenFindMethod", methodName.get());
}
}
首先,我们使用getInstance()工厂方法得到一个StackWalker实例,然后我们使用walk()方法从上到下遍历栈帧:
- walk()方法可以将堆栈帧流Stream
转换为任何东西 - 给定流中的第一个元素是堆栈上的顶部帧
- 堆栈上的顶部帧始终表示当前正在执行的方法
因此,如果我们从流中获取第一个元素,我们就可以知道当前正在执行的方法的详细信息。更具体地说,我们可以使用StackFrame.getMethodName()来查找方法名称。
2.1 优点
与其他方法相比(稍后会详细介绍),Stack-Walking API有以下几个优点:
- 无需创建虚拟匿名内部类实例 — new Object().getClass() {}
- 无需创建虚拟异常 — new Throwable()
- 无需急切地捕获整个堆栈跟踪,此操作可能会很昂贵
相反,StackWalker只是以一种惰性的方式逐个遍历堆栈。在这种情况下,它只获取顶部帧,而不是像stacktrace方法那样快速捕获所有帧。
最重要的是,如果你使用的是Java 9+,请使用Stack-Walking API。
3. 使用getEnclosureMethod
我们可以使用getEnclosureMethod() API得到正在执行的方法的名称:
void givenObject_whenGetEnclosingMethod_thenFindMethod() {
String methodName = new Object() {}
.getClass()
.getEnclosingMethod()
.getName();
assertEquals("givenObject_whenGetEnclosingMethod_thenFindMethod", methodName);
}
4. 使用Throwable Stack Trace
使用Throwable堆栈跟踪为我们提供了当前正在执行的方法的堆栈跟踪:
void givenThrowable_whenGetStacktrace_thenFindMethod() {
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
assertEquals("givenThrowable_whenGetStacktrace_thenFindMethod",
stackTrace[0].getMethodName());
}
5. 使用线程堆栈跟踪
此外,当前线程(从JDK 1.5开始)的堆栈跟踪通常包括正在执行的方法的名称:
void givenCurrentThread_whenGetStackTrace_thenFindMethod() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
assertEquals(
"givenCurrentThread_whenGetStackTrace_thenFindMethod",
stackTrace[1].getMethodName());
}
但是,我们需要记住,这种解决方案有一个明显的缺点。某些虚拟机可能会跳过一个或多个堆栈帧。虽然这并不常见,但我们应该意识到这可能会发生。
6. 总结
在本教程中,我们通过几个例子说明了如何获取当前执行的方法的名称。
与往常一样,本教程的完整源代码可在GitHub上获得。
Show Disqus Comments
Post Directory
扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章