屬于Kotlin中的委托屬性這一章中的標準委托
延遲屬性Lazy
lazy()
是接受一個lambda
并返回一個 Lazy <T>
實例的函數,返回的實例可以作為實現延遲屬性的委托。也就是說:
第一次調用get()
會執行已傳遞給 lazy()
的 lambda 表達式并記錄結果, 后續調用get()
只是返回記錄的結果。
這里需要注意的是 調用的是
get()
方法,和set沒啥關系
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
輸出結果為
computed!
Hello
Hello
同步鎖模式
防止對個線程同時初始化
默認情況下,對于 lazy
屬性的求值是同步鎖的(synchronized):該值只在一個線程中計算,并且所有線程會看到相同的值。如果初始化委托的同步鎖不是必需的,這樣多個線程可以同時執行,那么將 LazyThreadSafetyMode.PUBLICATION
作為參數傳遞給 lazy() 函數。 而如果你確定初始化將總是發生在單個線程,那么你可以使用 LazyThreadSafetyMode.NONE
模式, 它不會有任何線程安全的保證和相關的開銷。
延遲屬性Lazy 與 lateinit 區別
以下是lateinit var和by lazy { ... }委托屬性之間的顯著差異:
-
lazy { ... }
代表只能用于val
屬性,而lateinit
只能用于var
,因為它不能編譯到final字段,因此不能保證不變性; -
lateinit var
具有存儲值的后備字段(backing field)
,而by lazy { ... }
創建一個委托對象,其中存儲一次計算的值,將對代理實例的引用存儲在類對象中,并為與委托實例一起使用的屬性生成getter。 - 除了val之外,
lateinit
不能用于可空屬性和Java原語類型(這是因為null用于未初始化的值);所以如果你需要在類中存在的支持字段,請使用lateinit;
lateinit var
可以從對象被看到的任何地方被初始化。從一個框架代碼的內部,多個初始化方案是可能的單一類的不同對象。by lazy { ... }
反過來又定義了屬性的唯一初始化器,只能通過覆蓋子類中的屬性進行更改。如果您希望以預先未知的方式從外部初始化屬性,請使用lateinit。 - 另外,還有一個方法沒有提到Delegates.notNull(),它適用于non-null屬性的延遲初始化,包括Java原始類型的屬性。
延遲屬性Lazy 與 lateinit 使用總結
lateinit
用于外部初始化:當需要外部資料通過調用方法初始化您的值時。
例如通過調用:
private lateinit var value: MyClass
fun init(externalProperties: Any) {
value = somethingThatDependsOn(externalProperties)
}
而lazy
當它只使用對象內部的依賴關系時。
嗯。靜態變量的初始化挺適合這種方式的。