Kotlin 懒初始化值

Kotlin 懒初始化值:深入理解 lateinitby lazy

在 Kotlin 开发中,懒初始化(Lazy Initialization) 是一种常见的优化技巧,它允许我们将对象的初始化延迟到真正需要使用时再执行。Kotlin 提供了两种核心机制来实现懒初始化:lateinitby lazy。本文将深入探讨它们的使用场景、区别以及最佳实践。


一、lateinit:延迟赋值的 var 变量

1. 基本语法

kotlin 复制代码
class Example {
    lateinit var data: String

    fun initializeData() {
        data = "Initialized"
    }
}

2. 特点

  • 仅适用于 var 变量 :因为 lateinit 的本质是延迟赋值。
  • 非空类型支持 :允许你声明一个非空类型(如 String)而不立即初始化。
  • 手动控制初始化时机:需要开发者显式赋值。
  • 线程不安全:多线程环境下需手动同步。

3. 使用场景

  • Android 开发中初始化 ViewViewModel(例如在 onCreate 之后赋值)。
  • 依赖注入框架(如 Dagger/Hilt)管理的对象。
  • 初始化逻辑复杂且需要多次修改的属性。

4. 注意事项

  • 未初始化访问会抛出异常

    kotlin 复制代码
    lateinit var value: String
    println(value) // 抛出 UninitializedPropertyAccessException

二、by lazy:延迟计算的 val 变量

1. 基本语法

kotlin 复制代码
class Example {
    val computedValue: Int by lazy {
        // 首次访问时计算
        expensiveComputation()
    }

    private fun expensiveComputation(): Int {
        return 42 // 模拟耗时操作
    }
}

2. 特点

  • 仅适用于 val 不可变变量:初始化后值不可变。
  • 线程安全 :默认线程安全(使用 LazyThreadSafetyMode.SYNCHRONIZED)。
  • 延迟计算:首次访问时执行初始化逻辑。
  • 委托模式实现 :底层基于 Lazy<T> 接口。

3. 线程安全模式

Kotlin 提供三种线程安全模式:

kotlin 复制代码
val lazyValue: String by lazy(LazyThreadSafetyMode.NONE) { /* 非线程安全 */ }
val lazyValue: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { /* 默认 */ }
val lazyValue: String by lazy(LazyThreadSafetyMode.PUBLICATION) { /* 多次调用直到返回非空 */ }

4. 使用场景

  • 单例模式(如全局配置、数据库连接)。
  • 资源密集型对象(如图片加载器、网络客户端)。
  • 需要保证初始化一次且只读的属性。

三、lateinit vs by lazy 对比

特性 lateinit by lazy
支持类型 var val
初始化逻辑 手动赋值 Lambda 表达式定义
线程安全 默认线程安全
是否可变
异常行为 访问未初始化变量抛出异常 第一次访问时计算,无异常风险
典型使用场景 Android View、依赖注入对象 单例、资源密集型对象、只读配置

四、进阶技巧与注意事项

1. lateinit 的空安全检查

Kotlin 1.2+ 支持通过反射检查是否已初始化:

kotlin 复制代码
if (::data.isInitialized) {
    println("Data is initialized: $data")
}

2. by lazy 的异常处理

初始化 Lambda 中的异常会缓存并延迟到首次访问时抛出:

kotlin 复制代码
val riskyValue: Int by lazy {
    throw RuntimeException("Init failed")
}

// 使用时才会抛出异常
try {
    println(riskyValue)
} catch (e: Exception) {
    println(e.message) // 输出 "Init failed"
}

4. 避免滥用

  • 不要过度使用 lateinit,可能导致难以追踪的空指针问题。
  • by lazy 的初始化逻辑应尽量无副作用。

参考文档

相关推荐
悦悦子a啊1 小时前
Python之--集合
开发语言·python·编程
运维帮手大橙子1 小时前
字符串缓冲区和正则表达式
java·开发语言
慢慢沉2 小时前
Lua(数据库访问)
开发语言·数据库·lua
GISer_Jing2 小时前
50道JavaScript基础面试题:从基础到进阶
开发语言·javascript·ecmascript
Python涛哥2 小时前
PHP框架之Laravel框架教程:1. laravel搭建
开发语言·php·laravel
一百天成为python专家3 小时前
数据可视化
开发语言·人工智能·python·机器学习·信息可视化·numpy
武子康6 小时前
Java-82 深入浅出 MySQL 内部架构:服务层、存储引擎与文件系统全覆盖
java·开发语言·数据库·学习·mysql·spring·微服务
惜.己7 小时前
pytest中使用skip跳过某个函数
开发语言·python·测试工具·pytest
姜暮儿7 小时前
C++ 性能优化
开发语言·c++
啊呦.超能力8 小时前
QT开发---多线程编程
开发语言·qt