1. 概述

本文将介绍几种在 Kotlin 中获取当前执行函数名称的方法。

如果你使用的是 Java 9 及以上版本,第一种方法是最推荐的。除此之外,我们还会介绍一些“非主流”方式,虽然它们确实能工作,但往往伴随着一些性能或兼容性上的问题,属于“踩坑级”方案。

2. 使用 Stack-Walking API

Java 9 引入了 Stack-Walking API,用于惰性遍历当前线程的调用栈帧。相比传统方式,该 API 更加高效,因为它不会一次性捕获所有栈帧,也不会创建多余的中间对象。

每个栈帧代表一次方法调用,栈顶帧即为当前正在执行的方法。我们可以从中提取方法名:

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

walk() 方法接收一个函数式接口,参数是 StackFrame 的流。我们只需获取第一个栈帧,因此调用 findFirst(),并通过 methodName 获取当前函数名。

✅ 示例验证:

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

⚠️ 注意:该方法仅适用于 Java 9 及以上版本。

3. 使用匿名内部类

通过在函数内部定义一个匿名内部类,我们可以借助 Java 的 Class API 获取其外围方法名:

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

在 Java 中等价写法为:

new Object() {};

Kotlin 中的 object {} 会在编译时生成一个匿名类,我们通过 enclosingMethod.name 获取其定义所在的函数名。

✅ 示例验证:

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

❌ 缺点:这种方式会创建一个无意义的临时对象,效率较低,仅建议在 JVM 版本低于 Java 9 时使用。

4. 捕获堆栈跟踪信息

Thread.currentThread().getStackTrace() 返回当前线程的堆栈跟踪信息。我们可以通过它来获取当前执行的方法名:

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

⚠️ 注意:getStackTrace() 返回的数组中,第 0 项是 getStackTrace() 本身,第 1 项才是调用它的函数。

❌ 缺点:该方法会一次性捕获整个堆栈,性能较差,不建议频繁使用。

5. 总结

我们介绍了三种主要方式来获取当前执行函数的名称:

方法 适用版本 效率 推荐程度
Stack-Walking API Java 9+ ✅ 高 ✅ 强烈推荐
匿名内部类 Java 6+ ❌ 低 ⚠️ 用于兼容旧版本
堆栈跟踪 Java 1+ ❌ 最低 ❌ 不推荐

如无特殊兼容性要求,推荐优先使用 Stack-Walking API

所有完整代码示例可在 GitHub 仓库 中找到。


原始标题:Get the Name of the Currently Executing Function in Kotlin