今天我們介紹 Kotlin 中的兩個新特性:
-
lazy initialization
(懶初始化),即:推遲一個變量的初始化時機(jī)。這是個十分方便的特性于购,因為我們通常會遇到這樣的情況涯曲,一個變量直到使用時才需要被初始化
語法:Initialization by Lazy
(懶初始化)
例如:val myUtil by lazy { MyUtil(parameter1, parameter2)}
上面這段代碼創(chuàng)建了一個MyUtil
類型的對象芽卿。MyUtil
類型的對象只創(chuàng)建一次,就是第一次使用myUtil
的時候. -
Late Initialization
(延遲初始化)
語法:lateinit var myUtil: MyUtil
設(shè)置好延遲初始化后在以后的某個函數(shù)中
myUtil = MyUtil(parameter1, parameter2)
進(jìn)行初始化
大致來說就是將初始化與定義變量分離開來。
為什么有兩種方式抑淫?使用場景如何绷落?
盡管兩種方式有著相同的理念,本質(zhì)上卻有著很大的差異始苇。簡單地看下變量的類型砌烁,一個是 val(值不可變),另一個是 var(值可變)埂蕊。這已經(jīng)很能說明問題了往弓。下面是一些典型的使用場景單例變量
有時疏唾,我們需要的只是變量的單個實(shí)例,全局共享這個變量
MyUtil getMyUtil() {
if (myUtil == null) myUtil = new MyUtil(param1, param2);
return myUtil;
}
這在單例模式中是非常常見的函似,我們可以確保所有地方訪問的都是同一個實(shí)例槐脏。同時也能保證這個對象只在我們需要時被創(chuàng)建。在這種情況下撇寞,Lazy Initialization(懶初始化模式) 將很有用顿天。
初始化一個不可為空的變量
在 Kotlin 中,我們需要預(yù)先定義好一個變量是否可為空蔑担。這使得編譯器能在編譯時識別出潛在的 null 對象牌废,以避免 NPE (空指針異常)。
因此啤握,對于一個不可為空的成員變量鸟缕,當(dāng)類被創(chuàng)建時,它必須要被賦予一個非空的值排抬。如果在類被創(chuàng)建時懂从,初始化這個成員變量的所有依賴對象都已經(jīng)準(zhǔn)備好,那當(dāng)然就不是問題了蹲蒲。不幸的是番甩,有些情況下,這些依賴對象(例如上述例子中的 param1 和 param2)需要等到相關(guān)依賴對象都準(zhǔn)備好了才能給它初始化届搁。
基于這種情況缘薛,lateinit(延遲初始化模式) 給我們帶來了便利,Kotlin 以優(yōu)雅的方式允許一個成員變量在定義時是未初始化的卡睦,之后當(dāng)一切準(zhǔn)備就緒了再執(zhí)行它的初始化宴胧。。
使用依賴注入的變量
如果你在 Kotlin 中使用了依賴注入框架(例如 Dagger2
)么翰,那些預(yù)先聲明的變量也無法成功初始化牺汤。在這種情況下,必須使用 lateinit
關(guān)鍵字確保變量在稍后將被初始化浩嫌。
@Inject
lateinit var myUtil: MyUtil
實(shí)際上檐迟,lateinit
關(guān)鍵字就是因為這個原因而在 Kotlin 中明確地引入的。
何時用码耐?用哪個追迟?
上述例子僅是一小部分使用情境。事實(shí)上只要是不可為空的變量骚腥,很多情況下都是適用的敦间。有一些簡單的規(guī)則來幫助你決定該用哪一個模式:
- 如果是值可修改的變量(即在之后的使用中可能被重新賦值),使用
lateInit
模式 - 如果變量的初始化取決于外部對象(例如需要一些外部變量參與初始化),使用
lateInit
模式廓块。這種情況下厢绝,lazy
模式也可行但并不直接適用。 - 如果變量僅僅初始化一次并且全局共享带猴,且更多的是內(nèi)部使用(依賴于類內(nèi)部的變量)昔汉,請使用
lazy
模式。從實(shí)現(xiàn)的角度來看lateinit
模式仍然可用拴清,但lazy
模式更有利于封裝你的初始化代碼靶病。
綜上所述,不考慮對變量值是否可變的控制口予,lateinit
模式是 lazy
模式的超集(不是繼承關(guān)系,而是lateinit便利程度大于lazy)娄周,你可以在任何使用 lazy
模式的地方用 lateinit
模式替代,反之則不然沪停。但在可能的情況下煤辨,請盡量使用 lazy
模式,因為 lateinit
模式在函數(shù)中暴露了太多的邏輯代碼牙甫,使得代碼更加混亂掷酗,相比而言,lazy
模式更好地封裝了細(xì)節(jié)窟哺,且更安全。
總結(jié)而言技肩,對于變量的初始化且轨,優(yōu)先選擇 lazy
模式,其次再考慮 lateinit
模式……實(shí)在不行虚婿,選擇最原始的方法手動實(shí)現(xiàn).