當我們把Java自動轉成Kotlin的時候,代碼裏會出現很多非空斷言!!
。或者某些場景下因爲IDE提示或編譯錯誤,也讓我們自己加上了一些!!
。
但使用!!
的後果是有可能拋出IllegalArgumentException:Parameter specified as non-null is null
。
如何避免!!
?
使用?.let/?.apply/?.run
這種是最常用的方法,也是首選的方法。但當有多個變量同時要判空時,或者需要處理爲null時的邏輯,這種方式稍微有一點麻煩,下面會講到一些新的方式。
disposable?.let {
if (!it.isDisposed) it.dispose()
}
用Val替代Var
var mutableString:String? = null
fun run() {
mutableString = "a"
printText(mutableString)
}
fun printText(text: String) {
...
}
此時會報錯`Smart cast to 'String' is impossible, because 'multableString' is a mutable property that could have been changed by this time
:app:compileDebugKotlin FAILED`。由於multableString是Var變量,爲了避免多線程對變量的修改而出現Null的情況,kotlin從編譯上進行了限制。
- 解決方法1是把var變量改爲val變量
val mutableString:String = "a"
fun run() {
printText(mutableString)
}
- 解決方法2是寫一個新的val變量,將var變量賦值給它,將val作爲參數
fun run() {
mutableString = "a"
val string = mutableString ?: ""
printText(string)
}
<!-- more -->
使用Elvis操作符
fun run() {
multableString = "a"
printText(multableString ?: "")
}
聲明lateinit
使用lateinit
聲明到變量上,表示這個變量延遲初始化,比較適合在Activity.onCreate
這種有生命週期的方法裏初始化。
lateinit var mutableString: String
override fun onCreate(savedInstanceState: Bundle?) {
multableString = "a"
printText(mutableString)
}
需要注意的是,訪問未初始化的 lateinit 修飾的屬性會拋出UninitializedPropertyAccessException異常
注意:基本類型是不能使用lateinit
的。會拋錯'lateinit' modifier is not allowed on properties of primitive types
。
lateinit var mutableInt: Int
代理屬性
如果需要對基本類型等做非空處理,可以使用代理屬性。
var mutableInt: Int by Delegates.notNull<Int>()
override fun onCreate(savedInstanceState: Bundle?) {
mutableInt = 1
}
一定要在初始化賦值之後才能讀取mutableInt
,不然會拋IllegalStateException:Property ${property.name} should be initialized before get.
空與非空處理
val result = multableString.notNullElse {
"$it is not null"
} ({ "is null" })
新開發的方法notNullElse
,對單個變量判空處理,非空時傳入it
爲非空類型,提高了便捷性,爲空時使用第二個block來返回值。適合那裏需要判空,返回值result
也是非空的類型,比較實用。源碼在此下載
多個值非空
private var mLinearLayout: LinearLayout? = null
...
private fun initView(context: Context) {
mLinearLayout = LinearLayout(context)
}
...
if (tvItem == null) {
mLinearLayout!!.addView(childTvItem)
} else {
mLinearLayout!!.addView(childTvItem, mLinearLayout!!.indexOfChild(tvItem) + 1)
}
當我們要對多個值判斷的時候,let
就不那麼好用了,但如果不使用let
就拿不到非空的類型,像上面要判斷2個都不爲空時做操作,爲空時另外一個邏輯。其實一早我們就已經判斷空了,有沒有更好的方法呢?
allNotNullElse(tvItem, mLinearLayout) { a, b ->
b.addView(childTvItem, b.indexOfChild(tvItem) + 1)
} ({ mLinearLayout?.addView(childTvItem) })
新開發的方法allNotNullElse
返回的a, b 兩個值已經是非空類型了,這樣addView
使用的也是非空類型,使用起來更方便了。源碼在此下載
喜歡這篇文章,請點贊收藏,謝謝!