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
相关推荐
weixin_440784114 小时前
【HandlerThread实现原理】
android·java·开发语言
天空'之城4 小时前
C 语言工业级通用组件手写 24:互补滤波
c语言·开发语言·互补滤波·嵌入式算法·工业级组件
XR1234567884 小时前
工厂车间无线网络方案对比:AGV漫游哪家强?
开发语言·php
傻啦嘿哟4 小时前
某短视频平台视频爬虫实战:抓取推荐流视频信息,绕过反爬的3种技巧
开发语言·爬虫·python
現実君5 小时前
【硬件进阶】AD22上位替换JLEDA教程
开发语言·php
mubei-1235 小时前
SpringDAO的用法
java·开发语言·数据库
唐诺6 小时前
Android USB ADB 调试方案完全解析
android·adb·usb
格林威7 小时前
多相机微秒级对齐:硬件触发 vs PTP(IEEE 1588)方案实战对比
开发语言·人工智能·数码相机·机器学习·计算机视觉·视觉检测·机器视觉
初级代码游戏9 小时前
iOS开发 Swift 速记2:三种集合类型 Array Set Dictionary
开发语言·ios·swift
寰宇星城10 小时前
AppActuator - 让 AI Agent 直接理解并操作运行中的 Android App
android