1. 概要

このチュートリアルでは、Kotlinで現在実行されている関数の名前を取得するいくつかの方法を理解します。

最初のアプローチは、Java9をターゲットにしている場合の最も慣用的な方法です。 それに加えて、間違いなく機能するが欠点が伴ういくつかのハッキーな方法についても説明します。

2. スタックウォーキングAPI

Java 9では、現在のスレッドのスタックフレームを遅延ナビゲートするためのStack-WalkingAPIが導入されました。 このAPIは、コストのかかるすべてのフレームを熱心にキャプチャしないため、スタックフレームをトラバースするためのより良い方法を提供します。 また、代替アプローチとは対照的に、余分な不要なオブジェクトを割り当てたり、新しいクラスを定義したりすることはありません。

各スタックの一番上のフレームは、最後の関数呼び出しを表します。 したがって、このAPIを使用して、最上位のスタックフレームから関数名を取得できます。

fun functionNameWithStackWalker(): String? {
    return StackWalker.getInstance().walk { frames ->
        frames.findFirst().map { it.methodName }.orElse(null)
    }
}

walk()メソッドは、StackFramesStreamを入力として受け取る関数を受け入れます。 このようにして、すべてのフレームを1つずつ怠惰にウォークスルーし、各フレームから目的の情報を抽出できます。

上記の関数では、最初または一番上のフレームのみが必要なので、 findFirst()メソッドを呼び出しています。 また、各StackFrameは、特定のフレームの詳細をカプセル化します。 この場合、 methodName property(Javaでは getMethodName())を使用して、現在の関数名を検索しました。

この関数が期待どおりに機能することを確認しましょう。

val name = functionNameWithStackWalker()
assertEquals("functionNameWithStackWalker", name)

3. 匿名のインナークラス

関数定義内で匿名内部クラスを定義できます。 JavaのクラスAPIでは、囲んでいるメンバーの詳細にアクセスできるため、匿名の内部クラスを定義することで現在の関数名を取得することもできます。

fun functionNameWithAnonymousInnerClass(): String {
    return object {}.javaClass.enclosingMethod.name
}

Kotlinのobject{}宣言に相当するJavaは次のとおりです。

new Object() {};

したがって、関数内で匿名の内部クラスを定義しています。 したがって、 enclosingMethod プロパティ(Javaでは getEnclosingMethod() method)を使用して囲み関数名を取得できます。

val name = functionNameWithAnonymousInnerClass()
assertEquals("functionNameWithAnonymousInnerClass", name)

このアプローチは、まったく不要なオブジェクトを作成しているため、効率が少し低下し、慣用句も少なくなります。 したがって、ターゲットのJVMバージョンが9未満の場合にのみ、これを使用する必要があります。

4. スタックトレースのキャプチャ

ThreadクラスのgetStackTrace()メソッドは、スレッドのスタックダンプを表すスタックトレース要素の配列を返します。 このメソッドとThread.currentThread()メソッドを一緒に使用して、現在のスレッドのすべてのスタックトレース要素をキャプチャできます。

fun functionNameWithStackTraces(): String {
    return Thread.currentThread().stackTrace[1].methodName
}

Thread.currentThread()。getStackTrace()を使用する場合、 getStackTrace()メソッドがスタックの最上位になります。 したがって、2番目の配列要素は囲んでいる関数を表します。

getStackTrace()メソッドは多くのスタックトレース要素を熱心にキャプチャするため、これは最も効率の悪いアプローチです。 したがって、これはできるだけ使用しないようにする必要があります。

5. 結論

この短いチュートリアルでは、現在実行中の関数の名前を取得するためのいくつかの異なるアプローチを見ました。

いつものように、すべての例はGitHubから入手できます。