在Kotlin中,如果你不想在构造函数内部或类主体顶部初始化一个类属性,你基本上有以下两个选项(来自语言引用):

延迟初始化

lazy()是一个接受lambda并返回lazy <T>实例的函数,它可以作为实现lazy属性的委托:第一次调用get()执行传递给lazy()的lambda并记住结果,后续调用get()只返回记住的结果。 例子 公共类Hello { val myLazyString:通过lazy {"Hello"} }

第一个调用和随后的调用,不管它在哪里,对myLazyString都会返回Hello

晚些时候初始化

Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class. To handle this case, you can mark the property with the lateinit modifier: public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } } The modifier can only be used on var properties declared inside the body of a class (not in the primary constructor), and only when the property does not have a custom getter or setter. The type of the property must be non-null, and it must not be a primitive type.

那么,既然这两种方法都能解决同一个问题,如何在这两种方法中正确选择呢?


当前回答

如果你使用一个不可改变的变量,那么最好使用by lazy{…在这种情况下,您可以确保它总是在需要时初始化,最多初始化1次。

如果你想要一个非空变量,可以改变它的值,使用lateinit var。在Android开发中,你可以在onCreate, onResume等事件中初始化它。注意,如果调用REST请求并访问这个变量,可能会导致一个异常UninitializedPropertyAccessException: lateinit属性yourVariable没有初始化,因为请求的执行速度比变量初始化快。

其他回答

非常简短和简洁的回答

lateinit:它最近初始化非空属性

与延迟初始化不同,lateinit允许编译器识别非空属性的值没有存储在构造函数阶段以进行正常编译。

延迟初始化

在Kotlin中实现执行惰性初始化的只读(val)属性时,by lazy可能非常有用。

懒人{…}在第一次使用已定义属性的地方执行其初始化式,而不是其声明。

Lateinit vs lazy

lateinit i)与可变变量[var]一起使用 lateinit var name: String //允许 lateinit val name: String //不允许

ii)只允许使用非空数据类型

    lateinit var name: String       //Allowed
    lateinit var name: String?      //Not Allowed

iii)这是对编译器的一个承诺,该值将在未来被初始化。

注意:如果你试图访问lateinit变量而没有初始化它,那么它会抛出UnInitializedPropertyAccessException异常。

懒惰的 i)延迟初始化是为了防止不必要的对象初始化。

ii)你的属性不会被初始化,除非你使用它。

iii)只初始化一次。下次使用它时,将从缓存中获取值。

iv)它是线程安全的(它在第一次使用的线程中初始化。其他线程使用缓存中存储的相同值)。

v)该属性只能为val。

vi)属性可以是任何类型(包括基本类型和空值,这是lateinit不允许的)。

顺便说一下lateinit和lazy

后期

仅用于可变变量,即var和非空数据类型

lateinit var name: String //允许为非空

你是在告诉编译器这个值将来会被初始化。

注意:如果你试图访问lateinit变量而没有初始化它,那么它会抛出UnInitializedPropertyAccessException异常。

lazy

延迟初始化是为了防止不必要的对象初始化。 除非你使用你的变量,否则它不会被初始化。 它只初始化一次。下次使用它时,将从缓存中获取值。 它是线程安全的。 变量只能为val且不可为空。

欢呼:)

如果您正在使用Spring容器,并且希望初始化不可空的bean字段,lateinit更适合。

    @Autowired
    lateinit var myBean: MyBean

除了热键的好答案之外,下面是我在实践中如何在这两个选项中进行选择:

Lateinit用于外部初始化:当你需要通过调用一个方法来初始化你的值时。

例如,通过呼叫:

private lateinit var value: MyClass

fun init(externalProperties: Any) {
   value = somethingThatDependsOn(externalProperties)
}

lazy是指它只使用对象内部的依赖关系。