Kotlin by lazy和lateinit的使用及区别

在 Kotlin 中,lateinitby lazy 都可以用来延迟初始化变量,但它们有不同的适用场景和使用方式。下面详细介绍它们的用法和区别。

1.lateinit

lateinit 关键字用于延迟初始化 可变 属性 (var),主要用于那些在声明时不能立即初始化,但保证在使用前会完成初始化的属性。lateinit 只能用于非空的 可变变量 ,且只能用于 类的属性(不能用于局部变量或常量)。

使用场景

lateinit 通常用于 Android 的 ContextViewPresenter 等需要在声明时无法立即赋值,但稍后会赋值的情况。

示例代码
Kotlin 复制代码
class Example {
    lateinit var text: String // 延迟初始化的变量

    fun initializeText() {
        text = "Hello, World!"
    }

    fun printText() {
        if (this::text.isInitialized) { // 检查是否已经初始化
            println(text)
        } else {
            println("text 未初始化")
        }
    }
}

fun main() {
    val example = Example()
    example.initializeText()
    example.printText() // 输出:Hello, World!
}
注意事项
  • 只适用于可变变量lateinit 只能用于 var 变量,不能用于 val
  • 非空类型lateinit 只能用于非空类型,不能用于原始数据类型(如 IntDouble 等)。
  • 是否初始化检查 :可以使用 this::property.isInitialized 检查属性是否已初始化,避免直接访问未初始化的变量引发异常。

2. by lazy

by lazy 适用于 不可变属性 (val),它的初始化只会在第一次被访问时触发,且结果会被缓存下来,以后每次访问时都返回相同的值。by lazy 可以用来延迟初始化那些计算量大或依赖其他数据的属性,通常适用于线程安全的场景。by lazy本身是一种属性委托。属性委托的关键字是by。

使用场景

适合用来初始化 只读变量,比如配置文件加载、耗时计算结果等。

示例代码
Kotlin 复制代码
class Example {
    val text: String by lazy {
        println("初始化 text")
        "Hello, Lazy!"
    }

    fun printText() {
        println(text) // 第一次访问时初始化
    }
}

fun main() {
    val example = Example()
    example.printText() // 输出:初始化 text\nHello, Lazy!
    example.printText() // 输出:Hello, Lazy!(不会再初始化)
}
注意事项
  • 只适用于只读变量by lazy 只能用于 val 变量,表示它是不可变的。
  • 线程安全by lazy 的默认模式是线程安全的(相当于 LazyThreadSafetyMode.SYNCHRONIZED),也可以选择其他模式,如 LazyThreadSafetyMode.PUBLICATIONLazyThreadSafetyMode.NONE
  • 延迟计算:只有在属性第一次被访问时才会初始化。

3. lateinitby lazy 的区别

特性 lateinit by lazy
适用类型 var 可变变量 val 不可变变量
适用数据类型 只能用于非空对象类型 适用于任何类型,包括基础数据类型
初始化时机 在使用前需要手动赋值 第一次访问时自动初始化
初始化次数 可以被多次赋值 只会被初始化一次
线程安全性 无内置的线程安全 默认是线程安全的(可更改模式)
使用场景 Android 中的 ContextView 计算量大的只读变量,懒加载
是否可检查初始化状态 可以使用 isInitialized 检查 无法检查是否已初始化

总结

  • 使用 lateinit :适用于那些需要稍后赋值且会被多次修改的对象属性,比如 Android 中的 ContextView
  • 使用 by lazy:适用于那些不需要立即初始化,且一旦初始化后不再改变的只读属性,比如计算密集型或一次性加载的属性。
  • 一般来说的话,lateinit一定要记得初始化,不然后面会爆异常UninitializedPropertyAccessException
相关推荐
认真的酒窝2 小时前
自己动手开发编译器(十一)语义分析
java·开发语言
wbs_scy4 小时前
Linux C++ 高并发编程:线程池全链路深度解析,从原理到手撕实现
java·开发语言
JAVA面经实录9174 小时前
Linux 常用命令完整知识体系
java·linux·开发语言·汇编
贪玩的蛋挞4 小时前
C#与闭包
开发语言·c#
端庄的战斗机5 小时前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
Full Stack Developme5 小时前
Java LRU 与 LFU 算法及应用
java·开发语言·算法
C语言小火车7 小时前
C++ 堆排序深度精讲:基于完全二叉树的选择排序进化,最坏情况 O(n log n) 的稳定王者
开发语言·c++·算法·排序算法·堆排序
机智的张尼玛7 小时前
我基于 Kotlin Multiplatform 实现了一套跨平台的弱网离线同步引擎
android·开源·kotlin
北冥you鱼7 小时前
abigen 最佳实践:从入门到精通,高效生成 Go 语言合约绑定
开发语言·golang·区块链
ALex_zry8 小时前
C++26 std::complex 结构化绑定详解:auto [re, im] = c
c语言·开发语言·c++