Kotlin内联函数比Java匿名类更便宜吗?

抬起头来:我正在从记忆中写下一些内容,所以我可能会有一些不正确的概念 .


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中的大类计数相同的问题?

谢谢,

回答(2)

3 years ago

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

编译内联函数调用时,传递给调用的lambdas会内联到函数体中,而函数体又在调用站点内联 . 这允许编译器不为lambda主体生成任何其他类或方法 .

Compilation of an inline function

关于Kotlin的幻灯片之一构建了@yole的汇编 . 不幸的是,我发现只有俄语的记录 . 其他幻灯片也有一些兴趣,你可以在那里找到更多关于非内联lambda的信息 .

通常,使用带有lambdas的内联函数的Kotlin代码比使用lambdas或Streams的相同Java代码工作得更快 . 所有代码绑定都是在编译时完成的,并且没有虚拟方法调用的运行时开销,也没有增加的方法计数,这对于Android来说很重要 .

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

我建议你自己尝试内联函数:你可以轻松地inspect the resulting bytecode;当然,对性能重要的特定用例做一些基准测试 .

3 years ago

Kotlin有一个 inline 关键字 . 如果你使用这个关键字,它不仅内联函数,而且你可以将lambda体看作是一个嵌套的作用域级别,这样你就可以 return 了!

示例(直接来自文档)

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

查看文档了解更多信息:

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

编辑:

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

使用高阶函数会产生某些运行时惩罚:每个函数都是一个对象,它捕获一个闭包,即在函数体中访问的那些变量 . 内存分配(包括函数对象和类)和虚拟调用都会引入运行时开销 . 但似乎在许多情况下,通过内联lambda表达式可以消除这种开销 .

因此,据我所知,它将内联函数并删除否则会产生的任何开销 .

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