Kotlin 别样的 Null Safety
文献地址:《null-safety》 首先要声明,后续文字,都是个人愚见,欢迎讨论指正。
为什么更新文章
有一段时间没有写技术文章了的,借口有很多,比如天太冷上海都下起了大雪,忙于业务... 等等,今天为什么想起来写技术文章,只是因为下午开会,同事反馈说小组里面对 Kotlin
的认知,可能还是停留在 Java
的习惯上。就像你现在让我去写 mac ,我想可能我也会下意识的写出个什么 xxxImpl
来。
为什么选择这个话题
可是,既然要写,为什么会选这个话题?可能随便百度谷歌一搜索,就已经有一大把关于这个话题的文章了的。我之所以选择这个话题,我觉得 ?
这个符号,真的不是 简单的 Null Safety
类型安全,又或者 永别了的 NPE
。什么时候使用 ?
? 到底是选择问题前置还是问题后置? 是要和你
后续程序设计层面` 考虑的。
漫漫长夜咱细聊
关于 Kotlin 的 可选性 optional
的语法使用,我在开头已经写了链接,这里我就不做翻译了的。optional
字面意思是可选的,这个是一个对于Java而言相对新的概念,代表一个东西可能有,也可能没用。那么既然一个 属性
或者 参数
表示了 optional
那么我们在设计的时候,就已经认定它会存在 null
的情况,所以在后续使用的过程中需要自己额外判断,当然你会说我这样写:
var group: Group? = null //类创建的时候,可为空
group?.child?.id?.... //把问题后置
确实没错,我们可以很任性的一直往后面 ?.
访问后续的方法或属性等然后进行一系列的操作。当然我个人也非常建议多使用 ?
,这样可以把问题后置
。但我这里要说的,如果这个 group
是持有类或者方法必要的参数,那么是否在初始化或者传参的时候,就必须要求有值呢?
lateinit var group: Group //类创建的时候必须给初始化
fun updateGroup(group: Group) // 不接受参数为空,调用方如果为空会crash,把问题前置
到底是选择问题前置
还是问题后置
,是依据情况而定。
问题前置可以及时的暴露问题,并且排查问题。
lateinit var imageView: ImageView
init {
imageView = findViewById(R.id.img) as! ImageView //如果id没有找到,这里就会crash
}
}
但是选择问题后置,声明属性的时候默认都是?
可空,那么在findViewById
的时候,就会逃避并且跳过
crash。
var imageView: ImageView ? = null
init {
imageView = findViewById(R.id.img) as? ImageView //如果id没有找到,这里不会crash
}
}
可是后续某一些场景情况下,由于这种方式,更偏向于:我们主动告诉编译器我并不是很care他是否有值,有值我就接着往后面操作,没有值,你什么都不需要做,最终导致可能界面一块空白,排查起来比较麻烦。又后者要拿一下view
本身的属性,代码写起来可能你也觉得有点痛苦。
imageView?.displayImage(....) //结果界面没有显示出来图片,因为imageView为空
if(imageView?.enable?:false){
//....写起来有点累
}
而问题后置,更适合于统一处理的情况。比如我有一个显示图片的方法:
//我有处理null异常情况的能力
fun ImageView.displayAvatarImage(url: String?) {
val url = url?:return
//....
}
上层并不需要每次都判断一下图片地址是否为空的情况,而是统一交给最后一个环节进行处理就可以了的。
这里其实可以再细聊引入另一个话题,初始化
原则,这里就不做展开了的,可以参考这里:《init-keywords》,虽然是 Swift
,但是从程序设计层面上,是可以借鉴的。
个人诚恳的愚见
无论是问题前置
还是问题后置
,个人建议,当访问一些不确定的东西的时候,尽量使用?
, is
,as?
等等,杜绝不加判断的就直接
!!访问操作
。 为了强化这个愚见
,假设一个可选的类型,可以理解为是一个对象,对象里面有两个值,一个是 none
,一个是具体的 somevalue
. 当你用?
的时候,等价于你很保守的访问了somevalue
,但是如果你直接!!
访问操作,就等价于强制性的访问value,但是 value
是 null
,就会跟 Java
一样的 NPE
的悲剧发生。说到这里我想引入一个解包
的概念,也就是庖丁解牛
,我们要去访问一个可选类型,要把他拆开,此时:
?
等价于 “hi,你里面有数据吗? 有的话给我,没的话,我想退出代码块或者找别人去啦”
!!
等价于 “管你有没有,我就是要找你拿数据,结果臣妾做不到啊,我没东西给你了的,只能NPE
crash了的!”
Null Safety ???
逗我???聊了这么多,为什么一直没有提到 Null Safety
, 我想表达的观点是:并不是把 Java covert to kotlin
就万事大吉,就什么也不用做了的,就Null Safety
了的。仅仅是编译器帮忙做了一些累赘的编码工作罢了(你可以看生成的.class,仅仅只是帮我们写了判空的if else罢了),不要被这个名词给蒙蔽了双眼,当你偷懒的时候,那么抱歉,Null Safety
就是一个笑话,启动起来照样崩溃!