【Kotlin】lateinit和lazy延迟初始化的区别

序言

在Kotlin中,确实有两种方式可以实现延迟初始化:lateinit 和 lazy。它们都允许你在需要时进行变量的初始化,但它们有一些区别。

lateinit

1 lateinit 关键字只能用于修饰可变的属性(var),不能用于不可变的属性(val)。

2 你可以在任何地方延迟初始化使用 lateinit,而不仅仅局限于顶层属性或对象属性。

3 需要注意的是,对于使用 lateinit 延迟初始化的属性,在使用前必须显式赋值,否则会引发异常。

lateinit var name: String

// 使用前必须显式赋值
name = "John Doe"
println(name)

4 延迟初始化的属性不能使用空安全操作符(?. 和 !!.),因为它们不能确定属性是否已经被正确初始化。

lazy

1 lazy 是一个函数,它接受一个 lambda 表达式作为参数,返回一个 Lazy<T> 实例。使用 by lazy 将该实例与属性关联起来。

2 lazy 只能用于修饰不可变的属性(val),不能用于可变的属性(var)。

3 lazy 的属性只会在首次访问时进行初始化,之后的访问将直接返回已经初始化的值。

4 lazy 属性是线程安全的,因此在多线程环境下可以安全使用。

val randomNumber: Int by lazy {
    
    
    println("Initializing random number")
    (0..100).random()
}

// 首次访问时进行初始化
println(randomNumber)
// 直接返回已经初始化的值
println(randomNumber)

示例

让我们看一个使用lateinit的示例

class Person {
    
    
    lateinit var name: String
    
    fun initializeName() {
    
    
        name = "John Doe"
    }
    
    fun printName() {
    
    
        if (::name.isInitialized) {
    
    
            println(name)
        } else {
    
    
            println("Name is not initialized yet.")
        }
    }
}

val person = Person()
person.initializeName()
person.printName()

在上面的代码中,我们定义了一个Person类,并创建了一个延迟初始化的可变属性name。在initializeName()方法中,我们给name属性赋值。然后,在printName()方法中,我们检查name属性是否已经被初始化,如果是,则打印名称;否则,打印未初始化的消息。

接下来,我们看一个使用lazy的示例:

val randomNumber: Int by lazy {
    
    
    println("Initializing random number")
    (0..100).random()
}

fun main() {
    
    
    println(randomNumber)
    println(randomNumber)
}

在上面的代码中,我们定义了一个不可变属性randomNumber,它使用lazy函数进行延迟初始化。在lazy函数的lambda表达式中,我们输出初始化消息并生成一个随机数。在main()函数中,我们两次打印randomNumber属性。

运行上述代码,输出将是:

Initializing random number
58
58

从输出结果可以看出,lazy属性只在第一次访问时进行初始化。第二次访问时,直接返回已经初始化的值,而不会再执行初始化代码块。

综上所述,lateinit和lazy之间的区别是:

1 lateinit需要在使用之前进行初始化,否则会抛出异常,而lazy在第一次访问时进行初始化,且不需要提前初始化。

2 lateinit不能用于原生类型,只能用于可空类型;而lazy可以用于任何可空类型。

3 lateinit只能在类内部声明,而lazy可以在任何作用域中声明。

4 lateinit只能使用var关键字声明,lazy可以使用val或var关键字声明。

5 lazy属性提供了内置的线程安全机制,确保只有一个线程能够进行初始化,而lateinit属性没有提供内置的线程安全机制,需要开发人员自己管理线程安全性。

6 lateinit属性的错误在运行时捕获,lazy属性的错误在编译时捕获。

猜你喜欢

转载自blog.csdn.net/qq_43358469/article/details/131823334
今日推荐