Kotlin如何避免“!!”(非空断言)

当我们把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)
}
复制代码
使用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使用的也是非空类型,使用起来更方便了。源码在此下载

喜欢这篇文件,请点赞收藏,谢谢!

转载于:https://juejin.im/post/5bd13ec5e51d457a772bdc34

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值