0Pricing
Kotlin Academy · 课时

by lazy:深入了解延迟初始化

探索延迟初始化模式:SYNCHRONIZED、PUBLICATION 和 NONE。

by lazy:深入了解延迟初始化 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。

什么是 by lazy?

by lazy 会将 val 的初始化延迟到第一次访问时执行。Lambda 表达式只运行一次,并缓存结果。

val greeting: String by lazy {
    println("Computing...")
    "Hello, Kotlin!"
}
fun main() {
    println(greeting) // prints Computing... then Hello, Kotlin!
    println(greeting) // prints Hello, Kotlin! (cached)
}

Lazy 语法

by lazy 委托接收一个 Lambda 表达式,其返回值类型会根据属性声明自动推断。

val pi: Double by lazy { Math.PI }
val appName: String by lazy { "MyApp v1.0" }
fun main() {
    println(pi)      // 3.141592653589793
    println(appName) // MyApp v1.0
}

SYNCHRONIZED 模式(默认)

默认情况下,lazy 使用 LazyThreadSafetyMode.SYNCHRONIZED:只有一个线程会初始化该值。

val heavyResource: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
    Thread.sleep(100) // simulate work
    "Resource ready"
}
fun main() { println(heavyResource) }

PUBLICATION 模式

PUBLICATION 允许多个线程并发初始化;最终采用第一个结果。适合初始化成本低且没有副作用的场景。

val config: Map<String, String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
    mapOf("host" to "localhost", "port" to "8080")
}
fun main() { println(config["host"]) }

NONE 模式

NONE 不产生同步开销。只有在单线程环境且性能很重要时才应使用它。

val singleThreadValue: Int by lazy(LazyThreadSafetyMode.NONE) {
    42
}
fun main() { println(singleThreadValue) }

类中的 Lazy

类中的 by lazy 会在第一次访问属性时初始化,适合执行与实例状态相关的高成本计算。

class DatabaseConnection(val url: String) {
    val pool: String by lazy {
        println("Connecting to $url")
        "Pool@$url"
    }
}
fun main() {
    val db = DatabaseConnection("localhost:5432")
    println(db.pool)
}

Lazy 与 lateinit

对于初始化过程复杂的 val,请使用 by lazy。对于由外部赋值的 var(例如在测试或依赖注入中),请使用 lateinit。

class MyService {
    val computed: List<Int> by lazy { (1..100).toList() }
    lateinit var injected: String
}
fun main() {
    val s = MyService()
    s.injected = "injected value"
    println(s.computed.size)
    println(s.injected)
}

isInitialized 检查

可以通过 .isInitialized() 检查 Lazy 属性是否已初始化,但只能通过委托引用进行检查。

val myLazy: String by lazy { "initialized" }
fun main() {
    val ref = ::myLazy
    // No direct isInitialized on val lazy, but we can check via delegate
    println(myLazy)
}

带依赖的 Lazy

Lazy 属性可以引用其他 Lazy 属性,从而构建延迟初始化链。

val baseUrl: String by lazy { "https://api.example.com" }
val usersUrl: String by lazy { "$baseUrl/users" }
val postsUrl: String by lazy { "$baseUrl/posts" }
fun main() {
    println(usersUrl)
    println(postsUrl)
}

实践:单例服务

在 object 声明中使用 by lazy,可以按需初始化重量级单例。

object Analytics {
    val client: String by lazy {
        println("Initializing analytics client")
        "AnalyticsClient@ready"
    }
}
fun main() {
    println("App started")
    println(Analytics.client) // initialized on first use
    println(Analytics.client) // cached
}

延迟编译正则表达式

编译正则表达式的成本很高。使用 by lazy 可以只编译一次并重复使用,避免反复产生开销。

val emailRegex: Regex by lazy {
    Regex("^[A-Za-z0-9+_.-]+@(.+)$")
}
fun isValidEmail(email: String) = emailRegex.matches(email)
fun main() {
    println(isValidEmail("user@example.com")) // true
    println(isValidEmail("bad-email"))         // false
}

快速检查

在单线程环境中,为了获得最高性能,应该使用哪种 Lazy 模式?

回顾

by lazy 会在第一次访问时运行一次 Lambda 表达式,并缓存结果。线程安全请选择默认的 SYNCHRONIZED,并发且幂等的初始化请选择 PUBLICATION,单线程性能场景请选择 NONE。

常见问题解答

「by lazy:深入了解延迟初始化」课时是免费的吗?

是的 — 「by lazy:深入了解延迟初始化」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。

「by lazy:深入了解延迟初始化」这节课中我会学到什么?

探索延迟初始化模式:SYNCHRONIZED、PUBLICATION 和 NONE。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Kotlin Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「by lazy:深入了解延迟初始化」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Kotlin Academy 课中编写并运行代码吗?

能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. by lazy:深入了解延迟初始化
  2. observable 与 vetoable 委托
  3. 编写自定义 ReadWriteProperty 委托
  4. 用于偏好设置、Map 支持属性和日志记录的委托
← 返回 Kotlin Academy