小谈Kotlin的空处理的使用

2019-07-31| 发布者: admin| 查看: |

总的来说 kotlin 为了解决 npe 做了大量语言层级的强限制,的确可以做到减少 npe 的发生。但这种既“契约式”又“防御式”的方案会让开发者做更多的工作,会更“麻烦”一点。

当然,kotlin 为了减少麻烦,用 “ ” 简化了判空逻辑 —— “ ” 的实质还是判空,我们可以通过工具查看 time .toint 的 java 等价代码是:

if  {
 int var10000 = time;

这种简化在数据层级很深需要写大量判空语句时会特别方便,这也是为什么 虽然逻辑上 kotlin 让开发者做了更多工作,但写代码过程中却并没有感觉到更麻烦。


在 kotlin 这么严密的防御之下,npe 问题是否已经被终结了呢?答案当然是否定的。在实践过程中我们发现主要有以下几种容易导致 npe 的场景:


例如从后端拿 json 数据的场景,后端的哪个字段可能会传空是客户端无法控制的,这种情况下我们的预期 必须是 每个字段都可能为空,这样转成 json object 时才不会有问题:

data class user

假如有一个字段忘了加上” ”,后端没传该值就会抛出空指针异常。


private lateinit var muser: user
private fun initview {
 muser = intent.getparcelableextra user 

在 kotlin 的体系中久了会过分依赖于 android studio 的空值检查,在代码提示中 intent 的 getparcelableextra 方法返回的是非空,因此这里你直接用方法结果赋值不会有任何警告。但点击进 getparcelableextra 方法内部你会发现它的实现是这样的:

public t extends parcelable t getparcelableextra {
 return mextras == null null : mextras. t getparcelable;
 }

内部的其他代码不展开了,总之它是可能会返回 null 的,直接赋值显然会有问题。

我理解这是 kotlin 编译工具对 java 代码检查的不足之处, 它无法准确判断 java 方法是否会返回空就选择无条件信任,即便方法本身可能还声明了 @nullable 。


这点与第一、第二点都很类似,主要是使用过程中一定要进一步思考传递过来的值是否真的非空。

有人可能会说,那我全部都声明为可空类型不就得了么 —— 这样做会让你在使用该变量的所有地方都需要判空,kotlin 本身的便利性就荡然无存了。

我的观点是不要因噎废食,使用时多注意点就可以避免大部分问题。


当将可空类型赋值给非空类型时,需要有对空类型的判断,确保非空才能赋值。

我们使用 !! 可以很方便得将“可空”转为“非空”, 但可空变量值为 null,则会 crash 。

因此使用上建议在确保非空时才用 !! :


否则还是尽量放在判空代码块里:

param .let {
 dosomething 

从 java 的空处理转到 kotlin 的空处理,我们可能会下意识去寻找对标 java 的判空写法:

if  {
 //非空如何 
} else {
 //为空又如何

在 kotlin 中类似的写法的确有,那就是结合高阶函数 let、apply、run …… 来处理判空,比如上述 java 代码就可以写成:

n .let {
 //非空如何
} : let {
 //为空又如何

但这里有几个小坑。


假如是 java 的写法,那么不管 n 的值怎样,两个代码块都是互斥的,也就是“非黑即白”。但 kotlin 的这种写法不是。

: 这个操作符可以理解为 if a else b ,也就是它之前的值非空返回之前的值,否则返回之后的值。

而上面代码中这些高阶函数都是有返回值的,详见下表: