【问题标题】:Are Kotlin inline functions less expensive than Java anonymous classes?Kotlin 内联函数是否比 Java 匿名类便宜?
【发布时间】:2017-10-18 23:38:59
【问题描述】:

请注意:我是凭记忆写的,所以我可能有些概念不正确。


Java 具有编写匿名函数的能力。当您有某种事件的侦听器接口时,这很有用。举个例子:

button.setOnClickListener(new View.OnClickListener(View v) {
    @Override
    public void onClick(View v) {
        // handle the action here
    }
});

匿名侦听器将被编译为类似OnClickListener$1.class 的类。这是 Java 语言的底层设计决策。一切都是对象,甚至是匿名函数。

当您想要编写功能更强大的代码库时,这会成为一个问题。大量匿名类会产生大量类数,这在 Android 等受限平台上可能会成为问题。

从源代码的角度来看,Kotlin 中的函数更加一流。我的问题是,Kotlin 将这些函数编译成字节码是否比 Java 对匿名类更有效,还是我会遇到与 Java 中的大类计数相同的问题?

谢谢,

【问题讨论】:

    标签: java kotlin


    【解决方案1】:

    简短的回答是是的,Kotlin 内联函数非常便宜。

    当编译内联函数调用时,传递给调用的 lambda 被内联到函数体中,而函数体又在调用点被内联。这允许编译器不为 lambda 主体生成任何额外的类或方法。

    the slides 之一是关于 Kotlin 构造由@yole 编译的。 不幸的是,我发现记录只有in Russian。其他幻灯片也很有趣,您可以在此处找到有关非内联 lambda 的更多信息。

    一般来说,使用带有 lambda 的内联函数的 Kotlin 代码比带有 lambda 或 Streams 的相同 Java 代码运行得更快。所有代码绑定都是在编译时完成的,没有虚拟方法调用的运行时开销,也没有增加方法的数量,这对 Android 很重要。

    过度内联的缺点是代码大小增长:内联函数体的字节码的公共部分实际上在调用站点被复制。此外,内联使调试复杂化,因为代码的行号和调用堆栈将与源文件中的不同。虽然 IDE 支持在这里可以提供帮助。

    我建议您自己尝试内联函数:您可以轻松inspect the resulting bytecode;当然,还可以对性能很重要的特定用例进行一些基准测试。

    【讨论】:

    • 嘿,我只想对您的深入回复表示感谢。这正是我想要的。
    【解决方案2】:

    Kotlin 有一个 inline 关键字。如果你使用这个关键字,它不仅可以内联函数,而且你可以将 lambda 主体视为只是一个嵌套的范围级别,这样你就可以从中 return

    示例(直接来自文档)

    fun foo() {
        inlineFunction {
            return // OK: the lambda is inlined
        }
    }
    

    查看文档了解更多信息:

    https://kotlinlang.org/docs/reference/inline-functions.html

    编辑:

    为了澄清您关于性能的确切问题,这是文档的第一段:

    使用高阶函数会带来一定的运行时惩罚:每个函数都是一个对象,并且它捕获一个闭包,即在函数体中访问的那些变量。内存分配(函数对象和类)和虚拟调用会引入运行时开销。

    但在很多情况下,这种开销似乎可以通过内联 lambda 表达式来消除。

    据我所知,它会内联函数并消除任何否则会产生的开销。

    但是,这似乎只适用于您声明为 inline 的函数。

    【讨论】:

    • 这不是我真正要问的,但谢谢。如果您将内联函数传递给将在编译的字节码中创建多个函数的高阶函数,是吗?
    猜你喜欢
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    相关资源
    最近更新 更多