天天看點

Kotlin學習系列——lateinit 和 by lazy

閱讀:Null檢查機制及lateinit與by lazy(委托機制)的應用

https://blog.csdn.net/Shenpibaipao/article/details/76974461

lateinit 和 lazy 是 Kotlin 中的兩種不同的延遲初始化的實作

lateinit 隻用于變量 var,而 lazy 隻用于常量 val
lazy 應用于單例模式(if-null-then-init-else-return),而且當且僅當變量被第一次調用的時候,委托方法才會執行。

lazy()

是接受一個 lambda 并傳回一個

Lazy <T>

執行個體的函數,傳回的執行個體可以作為實作延遲屬性的委托: 第一次調用

get()

會執行已傳遞給

lazy()

的 lambda 表達式并記錄結果, 後續調用

get()

隻是傳回記錄的結果。

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}
fun main(args: Array<String>) {
    println(lazyValue)
    println(lazyValue)
}
           

列印結果

computed!
Hello

Hello
           

比如這樣的常見操作,隻擷取,不指派,并且多次使用的對象

private val mUserMannager: UserMannager by lazy {
     UserMannager.getInstance()
}
           

再比如acitivity中控件初始化的操作,一般傳統的進入界面就初始化所有的控件,而使用懶加載,隻有用到時才會對控件初始化

//kotlin 封裝:
fun <V : View> Activity.bindView(id: Int): Lazy<V> = lazy {
    viewFinder(id) as V
}
//acitivity中擴充調用
private val Activity.viewFinder: Activity.(Int) -> View?
    get() = { findViewById(it) }
//在activity中的使用姿勢
val mTextView by bindView<TextView>(R.id.text_view)
mTextView.text="執行到我時,才會進行控件初始化"
           

val mLayoutContext:ViewGroup by lazy{
	findViewById(R.id.mLayoutContent) as ViewGroup
}
           
lateinit(延遲初始化屬性)

一般地,屬性聲明為非空類型必須在構造函數中初始化(我們知道,kotlin中預設是空安全的,任何屬性的聲明都必須有初始化值,如果支援可空”?”,才能把屬性聲明為null)。然而這樣經常不友善,例如:屬性可以通過依賴注入來初始化,或者單元測試的setup方法中初始化,這種情況下,你不能在構造函數内提供一個非空初始器,但你仍然想在類體中引用該屬性時避免空檢查。為處理這種情況,我們可以使用lateinit

val nameA:String //報紅線 提示如下 
Property must be initialized or be abstract

lateinit var name:String //lateinit可以避免這種情況
           

該修飾隻能用于類體中(不是在主構造函數中)聲明的var屬性,注意是var(可變屬性)并且僅當該屬性沒有自定義getter或setter時,該屬性必須是非空類型,并且不能是原生類型。

在初始化前通路一個lateinit屬性會抛出一個特定異常,該異常明确辨別該屬性被通路及它沒有初始化的事實。