1. Обзор
Иногда нам нужно знать имя текущего выполняемого метода Java.
В этой краткой статье представлена пара простых способов получить имя метода в текущем стеке выполнения.
2. Java 9: API обхода стека
В Java 9 появился API Stack-Walking для ленивого и эффективного обхода кадров стека JVM. Чтобы найти текущий выполняемый метод с помощью этого API, мы можем написать простой тест:
public 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());
}
Во- первых, мы получаем экземпляр StackWalker
, используя фабричный метод getInstance() .
Затем мы используем метод walk()
для обхода кадров стека сверху вниз:
- Метод
walk()
может преобразовать поток кадров стека —Stream< StackFrame > —
во что угодно . - Первый элемент в данном потоке — это верхний фрейм в стеке.
- Верхний фрейм в стеке всегда представляет текущий выполняемый метод.
Следовательно, если мы получим первый элемент из потока, мы будем знать детали выполняемого в данный момент метода. В частности, мы можем использовать StackFrame.getMethodName()
, чтобы найти имя метода.
2.1. Преимущества
По сравнению с другими подходами (подробнее о них позже) Stack-Walking API имеет несколько преимуществ:
- Нет необходимости создавать фиктивный экземпляр анонимного внутреннего класса —
new Object().getClass() {}
- Не нужно создавать фиктивное исключение —
новый Throwable()
- Нет необходимости жадно захватывать всю трассировку стека, что может быть дорогостоящим
Напротив, StackWalker
только лениво обходит стек один за другим. В этом случае он извлекает только верхний кадр, в отличие от подхода с трассировкой стека, который с готовностью захватывает все кадры.
Суть в том, что используйте Stack-Walking API, если вы используете Java 9+.
3. Использование метода getEnclosingMethod
Мы можем найти имя выполняемого метода с помощью API getEnclosingMethod()
:
public void givenObject_whenGetEnclosingMethod_thenFindMethod() {
String methodName = new Object() {}
.getClass()
.getEnclosingMethod()
.getName();
assertEquals("givenObject_whenGetEnclosingMethod_thenFindMethod",
methodName);
}
4. Использование Throwable
Stack Trace
Использование трассировки стека Throwable
дает нам трассировку стека с выполняемым в данный момент методом:
public void givenThrowable_whenGetStacktrace_thenFindMethod() {
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
assertEquals(
"givenThrowable_whenGetStacktrace_thenFindMethod",
stackTrace[0].getMethodName());
}
5. Использование трассировки стека потоков
Кроме того, трассировка стека текущего потока (начиная с JDK 1.5) обычно включает имя выполняемого метода:
public void givenCurrentThread_whenGetStackTrace_thenFindMethod() {
StackTraceElement[] stackTrace = Thread.currentThread()
.getStackTrace();
assertEquals(
"givenCurrentThread_whenGetStackTrace_thenFindMethod",
stackTrace[1].getMethodName());
}
Однако нужно помнить, что у этого решения есть один существенный недостаток. Некоторые виртуальные машины могут пропускать один или несколько кадров стека. Хотя это не является распространенным явлением, мы должны знать, что это может произойти.
6. Заключение
В этом уроке мы представили несколько примеров того, как получить имя выполняемого в данный момент метода. Примеры основаны на трассировке стека и методе getEnclosingMethod()
.
Как всегда, вы можете ознакомиться с примерами, представленными в этой статье , на GitHub . Также примеры Java 9 доступны в нашем модуле Java 9 GitHub .