kotlin进阶之路Android开发经验谈程序员

Kotlin 别样的 Null Safety

2018-02-06  本文已影响66人  IMSk

文献地址:《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,但是从程序设计层面上,是可以借鉴的。

个人诚恳的愚见

无论是问题前置还是问题后置,个人建议,当访问一些不确定的东西的时候,尽量使用?, isas? 等等,杜绝不加判断的就直接!!访问操作。 为了强化这个愚见,假设一个可选的类型,可以理解为是一个对象,对象里面有两个值,一个是 none,一个是具体的 somevalue. 当你用?的时候,等价于你很保守的访问了somevalue,但是如果你直接!!访问操作,就等价于强制性的访问value,但是 valuenull,就会跟 Java 一样的 NPE 的悲剧发生。说到这里我想引入一个解包的概念,也就是庖丁解牛,我们要去访问一个可选类型,要把他拆开,此时:

? 等价于 “hi,你里面有数据吗? 有的话给我,没的话,我想退出代码块或者找别人去啦”

!! 等价于 “管你有没有,我就是要找你拿数据,结果臣妾做不到啊,我没东西给你了的,只能NPE crash了的!”

Null Safety ???

逗我???

聊了这么多,为什么一直没有提到 Null Safety, 我想表达的观点是:并不是把 Java covert to kotlin 就万事大吉,就什么也不用做了的,就Null Safety了的。仅仅是编译器帮忙做了一些累赘的编码工作罢了(你可以看生成的.class,仅仅只是帮我们写了判空的if else罢了),不要被这个名词给蒙蔽了双眼,当你偷懒的时候,那么抱歉,Null Safety 就是一个笑话,启动起来照样崩溃!

上一篇下一篇

猜你喜欢

热点阅读