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
相关推荐
老狼孩111223 分钟前
2025新版懒人精灵零基础及各板块核心系统视频教程-全分辨率免ROOT自动化开发
android·机器人·自动化·lua·脚本开发·懒人精灵·免root开发
basketball61620 分钟前
Python torchvision.transforms 下常用图像处理方法
开发语言·图像处理·python
宁酱醇28 分钟前
各种各样的bug合集
开发语言·笔记·python·gitlab·bug
啊吧怪不啊吧35 分钟前
Linux常见指令介绍下(入门级)
linux·开发语言·centos
谷晓光36 分钟前
Python 中 `r` 前缀:字符串处理的“防转义利器”
开发语言·python
Tiger Z41 分钟前
R 语言科研绘图第 41 期 --- 桑基图-基础
开发语言·r语言·贴图
打死不学Java代码42 分钟前
PaginationInnerInterceptor使用(Mybatis-plus分页)
android·java·mybatis
chuxinweihui1 小时前
数据结构——二叉树,堆
c语言·开发语言·数据结构·学习·算法·链表
陈大大陈1 小时前
基于 C++ 的用户认证系统开发:从注册登录到Redis 缓存优化
java·linux·开发语言·数据结构·c++·算法·缓存
看到我,请让我去学习1 小时前
C语言基础(day0424)
c语言·开发语言·数据结构