Post

현재 실행중인 함수명 얻기

Java에서 실행중인 함수명을 얻는 여러 방법을 비교하고 소개합니다. 각각의 방법은 장단점이 있으니, 상황에 따라 알맞게 사용하길 권장합니다.

요약은 다음과 같습니다.

  • 유연함을 원하면 StackTrace를 사용하세요.
  • 간단함과 속도를 원하면 Reflection을 사용하세요.

벤치마킹 환경
Java17 correto 환경에서 100번의 워밍업10000번의 반복을 통해 추이를 관찰했습니다. 하지만 이런 마이크로벤치마킹은 대부분 큰 의미가 없으며 상황과 사용사례에 따라 달라질 수 있음을 이해해주시길 바랍니다.

📚 1. StackTrace 사용


StackTrace 방식은 Call Stack 을 추적하기 때문에, 단순히 해당 Method만 얻는 것 이상의 작업을 할 수 있습니다.
예를들어, 함수이름 구하는 기능을 Util Class에 static Method 형식으로 정의하거나, 특정 Annotation이 붙은 제일 가까운 메서드를 찾는 등의 작업이 가능합니다.

대신 Reflection에 비해 오버헤드가 발생합니다. 하지만 StackWalker(java9+)를 사용하면 2~3배로 그 차이가 크지 않습니다.

주의할 점이 있습니다. 일부 VM은 성능최적화를 위해 스택추적에서 몇몇 프레임을 생략할 수 있습니다. 이런 최적화는 런타임 중 점진적으로 일어나며 예측하기 매우 어렵습니다. 일반적인 상황에서 문제가 될 일은 거의 없으나, 이런 오류가 발생할 수 있음을 분명히 인지하고 있어야 합니다.

🌟 1-1. StackWalker(java9+) 사용


Java9+에서 StackTrace를 사용한다면 이 방법을 사용하세요.

다른 StackTrace 방법에 비해 월등한 장점을 가집니다.

  1. 가장 빠르고 오버헤드가 적습니다. 처음부터 모든 Stack을 추적하지 않고, 필요한 시점에서 탐색하는 Lazy방식이기 때문입니다. 성능차이가 심하며, Call Stack이 깊어질수록 그 차이는 더 심해집니다.
  2. 다양한 편의를 제공합니다. Call Stack 스킵, 필터링, 매핑 등 다양한 Stream API들과 함께 유연한 작업 정의가 가능합니다.
  3. walk()Optional을 반환합니다. Null처리가 편해집니다.
1
2
3
4
5
6
7
8
9
10
11
StackWalker stackWalker = StackWalker.getInstance();
StackFrame stackFrame = stackWalker.walk(stream -> stream
                .skip(0)
                .filter(frame -> {
                    // do some filter...
                    return true;
                })
                .findFirst())
                .get();

String methodName = stackFrame.getMethodName();

StackWalker.getInstance()Option을 인자로 받습니다. 이를 통해 Reflection Classinvoke를 스킵하는 등 섬세한 튜닝이 가능합니다.

1-2. Thread 사용


Java8 이하버전에서 고려할 수 있습니다. Thread에서 직접 stackTrace를 구합니다. 항상 모든 StackTrace를 구하기 때문에 성능이 떨어집니다.

1
String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();

1-3. Exception 사용


java8 미만 버전에서 Thread 사용보다 빠르다는 정보가 있습니다. 하지만 java8+에서는 해당문제가 개선되어 사용할 이유가 없습니다.

1
String methodName = new Throwable().getStackTrace()[0].getMethodName();

🔍 2. Reflection 사용


가장 간단하고 빠른 방법입니다. 하지만 익명객체를 이용하기 때문에 해당 함수에 한정된 정보만 사용가능합니다.

런타임에서 익명객체와 Reflection을 이용합니다.

1
2
String methodName = new Object() {}
                      .getClass().getEnclosingMethod().getName();

References


  • https://stackoverflow.com/questions/442747/getting-the-name-of-the-currently-executing-method
  • https://openjdk.org/jeps/259
  • https://www.baeldung.com/java-name-of-executing-method
This post is licensed under CC BY 4.0 by the author.

Trending Tags