You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中IntArray的lastIndex与size-1性能差异疑问:为何lastIndex执行更慢?

Kotlin中IntArray的lastIndex与size-1性能差异疑问:为何lastIndex执行更慢?

嘿,这个问题确实挺让人困惑的——明明翻Kotlin源码能看到lastIndex的实现就是size - 1,但实际跑起来却比直接写size - 1慢,我来帮你梳理下可能的原因:

  • 方法调用的额外开销
    虽然lastIndex的逻辑和size - 1完全一致,但它是一个扩展属性,在JVM层面会被编译成静态方法调用(类似IntArrays.getLastIndex(nums)的形式)。哪怕这个方法只有一行代码,初次执行时也会有方法入栈出栈的开销;而直接写nums.size - 1时,size对应JVM原生数组的length字段,是直接访问内存的操作,减法也是简单的算术运算,JVM能直接优化,没有额外的方法调用成本。

  • JIT编译的预热差异
    JVM的即时编译器(JIT)需要一定的执行次数才会把热点代码内联、优化。直接写size - 1的逻辑更直白,JIT能更快识别并优化;而lastIndex的方法调用,在初次测试的短时间内可能还没被JVM内联,所以会体现出性能差异。如果你把测试代码重复跑几千次,等JVM充分预热后,两者的性能差距会大幅缩小甚至消失——因为JIT会把lastIndex的getter方法直接内联成size - 1的逻辑。

  • 单次测试的误差干扰
    你当前的测试只跑了一次循环,单次执行的时间太短,System.nanoTime()的测量结果很容易受到JVM线程调度、垃圾回收等因素的干扰,误差很大。建议把整个测试逻辑封装成函数,重复执行上万次,然后计算平均耗时,这样得到的结果才更可信。

比如可以修改测试代码,像这样:

fun main() {
    val tar = 2
    val repeatCount = 100000

    // 预热JVM
    testSizeMinusOne(intArrayOf(0,1,2), tar)
    testLastIndex(intArrayOf(0,1,2), tar)

    // 正式测试
    var totalSizeMinusOne = 0L
    repeat(repeatCount) {
        totalSizeMinusOne += testSizeMinusOne(intArrayOf(0, 1, 2, 2, 3, 0, 4, 2), tar)
    }
    println("size-1 平均耗时:${totalSizeMinusOne / repeatCount} ns")

    var totalLastIndex = 0L
    repeat(repeatCount) {
        totalLastIndex += testLastIndex(intArrayOf(0, 1, 2, 2, 3, 0, 4, 2), tar)
    }
    println("lastIndex 平均耗时:${totalLastIndex / repeatCount} ns")
}

fun testSizeMinusOne(nums: IntArray, tar: Int): Long {
    var count = 0
    var i = 0
    val begin = System.nanoTime()
    val n = nums.size - 1
    while (i <= n) {
        if (nums[i] != tar) {
            nums[count++] = nums[i]
        }
        i++
    }
    return System.nanoTime() - begin
}

fun testLastIndex(nums: IntArray, tar: Int): Long {
    var count = 0
    var i = 0
    val begin = System.nanoTime()
    val n = nums.lastIndex
    while (i <= n) {
        if (nums[i] != tar) {
            nums[count++] = nums[i]
        }
        i++
    }
    return System.nanoTime() - begin
}

跑这个版本的测试,你会发现预热后两者的耗时差距几乎可以忽略。

最后总结一下:这种差异本质上是JVM层面方法调用与直接字段访问的临时性能差,当JVM充分优化后,两者的表现会趋于一致。日常开发中不用太纠结这个——除非你在写极致性能敏感的代码,否则lastIndex的可读性优势更值得优先考虑。

备注:内容来源于stack exchange,提问作者TblPK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 07:14:50