Kotlin内联函数

作者: 奔跑吧李博 | 来源:发表于2021-08-01 21:11 被阅读0次
  • kotlin内联函数是什么?

Kotlin里使用关键字 inline 来表示内联函数。其原理就是:在编译时期,把调用这个函数的地方用这个函数的方法体进行替换。

Java 方法执行的内存模型是基于 Java 虚拟机栈的:每个方法被执行的时候都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧入栈、出栈的过程。

也就是说每调用一个方法,都会对应一个栈帧的入栈出栈过程,如果你有一个工具类方法,在某个循环里调用很多次,那就会对应很多次的栈帧入栈、出栈过程。栈帧的创建及入栈、出栈都是有性能损耗的。

比如test方法中,重复调用多次sum方法:

fun test() {
        //多次调用 sum() 方法进行求和运算
        println(sum(1, 2, 3))
        println(sum(100, 200, 300))
        println(sum(12, 34))
    }

    /**
     * 求和计算
     */
    fun sum(vararg ints: Int): Int {
        var sum = 0
        for (i in ints) {
            sum += i
        }
        return sum
    }

为了避免多次调用 sum() 方法带来的性能损耗,最好改为调用一次方法,将方法内的代码插入到调用该方法的地方:

fun test2() {
        var sum = 0
        for (i in arrayOf(1, 2, 3)) {
            sum += i
        }
        println(sum)

        sum = 0
        for (i in arrayOf(100, 200, 300)) {
            sum += i
        }
        println(sum)

        sum = 0
        for (i in arrayOf(12, 34)) {
            sum += i
        }
        println(sum)
    }

用关键字 inline 标记函数,该函数就是一个内联函数。还是原来的 test() 方法,编译器在编译的时候,会自动把内联函数 sum() 方法体内的代码,替换到调用该方法的地方。查看编译后的字节码,会发现 test() 方法里已经没了对 sum() 方法的调用,凡是原来代码里出现 sum() 方法调用的地方,出现的都是 sum() 方法体内的字节码了。

将sum方法加入inline声明,即可实现test2方法同等的效率。

    inline fun sum(vararg ints: Int): Int {
        var sum = 0
        for (i in ints) {
            sum += i
        }
        return sum
    }
内联函数通常与高阶函数搭配使用——优化Lambda开销

在Kotlin中每次声明一个Lambda表达式,就会在字节码中产生一个匿名类。该匿名类包含了一个invoke方法,作为Lambda的调用方法,每次调用的时候,还会创建一个新的对象。可想而知,Lambda虽然简洁,但是会增加额外的开销。Kotlin 采用内联函数来优化Lambda带来的额外开销。

cost {
    println("hello")
}
inline fun cost(block: () -> Unit) {
    val start = System.currentTimeMillis()
    block()
    println(System.currentTimeMillis() - start)
}

比如说我们要计算 println("hello") 这段代码执行的时间,如果不加 inline 的话,那么调用 cost 就要创建 Lambda 表达式,函数调用,结果发现这些操作的时间就要大于 println("hello") 这段代码执行的时间,这样是完全没有必要的,所以我们加上 inline 之后,调用 println("hello"),实际上就等于下面这样:

  val start = System.currentTimeMillis()
    println("hello")
    println(System.currentTimeMillis() - start)

加上 inline 之后,cost 函数的调用开销没了,Lambda 表达式的创建开销也没了,这就是内联函数的作用,主要是对高阶函数的性能优化。

kotlin中的不少高阶函数,扩展函数都用了inline来修饰,标识为内联函数。

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
noinline :避免参数被内联

如果一个内联函数的参数里包含 lambda表达式,也就是函数参数,那么该形参也是 inline 的,举个例子:

inline fun test(inlined: () -> Unit) {...}

Kotlin引入了noinline关键字,可以加在不想要内联的参数开头,该参数便不会有内联效果。

fun main() {
    payFoo({
        println("I am inlined...")
    }, {
        println("I am not inlined...")
    })
}
 
inline fun payFoo(block1: () -> Unit, noinline block2: () -> Unit) {
    println("before block")
    block1()
    block2()
    println("end block")
}
参考:Kotlin总结之内联函数

相关文章

  • Kotlin 内联函数 inline

    Kotlin 中新增了「内联函数」,内联函数起初是在 C++ 里面的。 那在 Kotlin 中加入内联函数,是有什...

  • Kotlin内联函数

    kotlin内联函数是什么? Kotlin里使用关键字 inline 来表示内联函数。其原理就是:在编译时期,把调...

  • Kotlin内联函数

    Kotlin里使用关键 inline 来表示内联函数,那么到底什么是内联函数呢,内联函数有什么好处呢? 1. 什么...

  • kotlin的内联函数和扩展函数

    kotlin的内联函数和扩展函数 内联函数 https://www.jianshu.com/p/ab877fe72...

  • kotlin的内联函数的使用

    kotlin的内联函数属于kotlin的高级特性了,也是不同于java的区别之一;至于为什么kotlin要使用内联...

  • Kotlin实战学习笔记(八 高阶函数)

    1.声明高阶函数 kotlin Java-Kotlin 返回函数的函数 内联函数 // 代码生成到class文件中...

  • Kotlin 基础精华篇

    Kotlin 基础精华篇Kotlin 内联函数let、with、run、apply、alsoKotlin 协程学习...

  • Kotlin 协程学习总结

    Kotlin 基础精华篇Kotlin 内联函数let、with、run、apply、alsoKotlin 协程学习...

  • Kotlin 内联函数let、with、run、apply、al

    Kotlin 基础精华篇Kotlin 内联函数let、with、run、apply、alsoKotlin 协程学习...

  • Kotlin中的函数

    Kotlin中的函数 kotlin中的函数分为普通函数,泛型函数,内联函数,扩展函数,高阶函数以及尾递归函数 1 ...

网友评论

    本文标题:Kotlin内联函数

    本文链接:https://www.haomeiwen.com/subject/rfwcpltx.html