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
相关推荐
bzmK1DTbd1 天前
Git版本控制:Java项目中的分支管理与合并策略
java·开发语言·git
Rust研习社1 天前
为什么 Rust 没有空指针?
开发语言·后端·rust
kyriewen111 天前
WebAssembly:前端界的“外挂”,让C++代码在浏览器里跑起来
开发语言·前端·javascript·c++·单元测试·ecmascript
其实防守也摸鱼1 天前
CTF密码学综合教学指南--第九章
开发语言·网络·python·安全·网络安全·密码学·ctf
砚底藏山河1 天前
Python量化开发:2026最佳实时股票数据API接口推荐与对比
开发语言·windows·python
AlunYegeer1 天前
JAVA,以后端的视角理解前端。在全栈的路上迈出第一步。
java·开发语言·前端
私人珍藏库1 天前
【Android】聆听岛[特殊字符]聚合全网音乐[特殊字符]免费听歌下载神器[特殊字符] 聚合音乐平台|无损母带下载|歌词封面同步|免费无广告听歌工具
android·人工智能·工具·软件·多功能
hixiong1231 天前
C# OpenvinoSharp使用DINOv2模型进行图像相似度计算
开发语言·c#
DFT计算杂谈1 天前
自动化脚本一键绘制三元化合物相图
java·运维·服务器·开发语言·前端·python·自动化
YF02111 天前
Android触摸机制与自定义 View 实战
android·app