Kotlin -> lateinit 和 lazy 详解

lateinitlazy 详解

核心区别

特性 lateinit lazy
类型 可变属性修饰符 var 不可变属性委托 val
初始化时机 手动显式初始化,随时可变 首次访问时自动初始化,之后不可变
空安全 非空类型,但初始值可缺失 非空类型,保证有值
适用类型 不能用于基本类型(Int, Boolean等) 可用于任何类型
线程安全 不保证线程安全 默认线程安全SYNCHRONIZED模式
检查机制 使用前需确保已初始化,否则抛异常 自动处理初始化,不会抛出未初始化异常

lateinit 核心用法

kotlin 复制代码
// 声明
class User {
    lateinit var name: String
    
    fun initialize() {
        name = "John" // 手动初始化
    }
    
    fun greet() {
        if (::name.isInitialized) { // 检查是否已初始化
            println("Hello, $name")
        }
    }
}

最佳使用场景:

  • 依赖注入
  • Activity/Fragment中的视图绑定
  • 单元测试的setUp方法中
  • 需要推迟初始化但之后可能需要修改的属性

lazy 核心用法

kotlin 复制代码
// 基本用法
class User {
    val name: String by lazy { 
        println("Computing name...")
        "John" // 计算并返回初始值
    }
}

// 指定线程安全模式
val expensiveData: List<Data> by lazy(LazyThreadSafetyMode.PUBLICATION) {
    loadDataFromDatabase()
}

线程安全模式:

  • SYNCHRONIZED:默认模式,线程安全,只执行一次初始化
  • PUBLICATION:多线程可能执行多次,但只有第一个结果被使用
  • NONE:不保证线程安全,适用于单线程环境,性能最好

最佳使用场景:

  • 计算开销大的属性
  • 需要根据条件计算的只读属性
  • 单例模式实现
  • 配置项和缓存数据

核心实现原理

lateinit

  • 在字节码级别,不为属性分配默认值
  • 访问前不进行空检查
  • 使用前若未初始化,抛出UninitializedPropertyAccessException

lazy

  • 内部使用SynchronizedLazyImpl等实现类
  • 持有一个初始化器函数和一个存储结果的AtomicReference
  • 首次访问时执行初始化器并缓存结果

如何选择

  • 如果属性需要在初始化后修改,使用lateinit var
  • 如果属性是只读的且可以延迟计算,使用lazy val
  • 如果处理基本类型,只能使用lazy
  • 如果在多线程环境中,优先考虑lazy
相关推荐
潼心1412o17 分钟前
C语言(长期更新)第15讲 指针详解(五):习题实战
c语言·开发语言
Murphy_lx1 小时前
Lambda表达式
开发语言·c++
yangpipi-1 小时前
C++并发编程-23. 线程间切分任务的方法
开发语言·c++
雨白2 小时前
实现双向滑动的 ScalableImageView(上)
android
木头左2 小时前
结合机器学习的Backtrader跨市场交易策略研究
人工智能·机器学习·kotlin
爬虫程序猿2 小时前
利用 Java 爬虫获取淘宝商品 SKU 详细信息实战指南
java·开发语言·爬虫
F2E_Zhangmo2 小时前
基于cornerstone3D的dicom影像浏览器 第五章 在Displayer四个角落显示信息
开发语言·前端·javascript
He1955012 小时前
Go初级之十:错误处理与程序健壮性
开发语言·python·golang