资讯专栏INFORMATION COLUMN

Kotlin可空性探索

DataPipeline / 1801人阅读

摘要:可空性在中,类型系统区分一个引用是可以容纳可空引用还是不能容纳非空引用。使用可以很方便得将可空转为非空,但可空变量值为,则会。

目录介绍

01.可空性

02.安全调用运算符:?.

03.Elvis运算符:?:

04.安全转换运算符:as?

05.非空断言:!!

06.let函数说明

07.可空类型的扩展

08.Java中判断方式

09.kotlin是否解决NPE

10.kotlin如何约束非空判断

11.导致NPE的场景

想换个工作,渴望同行内推我

个人信息

姓名:杨充【26岁】

邮箱:yangchong211@163.com

微信:13667225184

GitHub:https://github.com/yangchong211

博客汇总:https://github.com/yangchong2...

干活集中营:Android端技术博客和开源项目审核员

目前工作情况:在职状态

技术项目和博客:GitHub项目7k以上star,follower1.1k以上,发表博客100多篇。

热爱技术:开源项目和博客多次被鸿洋,郭霖,Android技术周刊,干活集中营等等推荐。

学历:武汉软件工程职业学院,大专学历

工作年限:3年多

工作地点:北京

关于近期投递简历一点感想

从进入Android这个行业以来,前两次几乎都是朋友内推,面试机会相对容易,都是一个App一个人做或者两个人做,用户相对来说并不多。这次想着离职,主要是想进入一个较大的平台,大概可以理解为Android端有个至少四五人,可以进行技术交流,渴望自己能够在技术上突破,这就像自己平时独自跑步,和跟着一群跑马拉松的人跑步,那种紧张感肯定是不一样的。

近段时间,尝试着向一些较大的公司投递简历,大概在拉钩上投了15个左右(不喜欢海投),发现绝大多数简历到不了技术那里,就被人事说学历不够,经验不够,工作不匹配等情况回绝。不过也可以理解,看简历无非就是学历和经验,貌似自己的履历是差了一点。

这大概是第一次在网上发一个主动希望同行内推的介绍,如果你的公司有Android方面的招聘,能否内推一下我这个小人物,感谢。

01.可空性

在 Kotlin 中,类型系统区分一个引用是可以容纳 null (可空引用)还是不能容纳(非空引

用)。 例如,String 类型的常规变量不能指向 null

</>复制代码

  1. var name: String = "yc"
  2. //编译错误
  3. //name = null

如果希望一个变量可以储存 null 引用,需要显式地在类型名称后面加上问好来标记它:

</>复制代码

  1. var name: String? = "yc"
  2. name = null

问号可以加在任何类型的后面来表示这个类型的变量可以存储 null 引用:Int?、Doubld? 、Long? 等

Kotlin 对可空类型的显式支持有助于防止 NullPointerException 导致的异常问题,编译器不允许不对可空变量做 null 检查就直接调用其属性

</>复制代码

  1. fun check(name: String?): Boolean {
  2. //编译器不允许不对 name 做 null 检查就直接调用其属性
  3. return name.isNotEmpty()
  4. }

需要显式地进行 null 检查

</>复制代码

  1. fun check(name: String?): Boolean {
  2. if (name != null) {
  3. return name.isNotEmpty()
  4. }
  5. return false
  6. }

02.安全调用运算符:?.

安全调用运算符:?.

允许把一次 null 检查和一次方法调用合并为一个操作,如果变量值非空,则方法或属性会被调用,否则直接返回 null

例如,以下两种写法是完全等同的:

</>复制代码

  1. fun check(name: String?) {
  2. if (name != null) {
  3. println(name.toUpperCase())
  4. } else {
  5. println(null)
  6. }
  7. }
  8. fun check(name: String?) {
  9. println(name?.toUpperCase())
  10. }

03.Elvis运算符:?:

Elvis 运算符:?:

用于替代 ?. 直接返回默认值 null 的情况,Elvis 运算符接收两个运算数,如果第一个运算数不为 null ,运算结果就是其运算结果值,如果第一个运算数为 null ,运算结果就是第二个运算数

例如,以下两种写法是完全等同的:

</>复制代码

  1. fun check(name: String?) {
  2. if (name != null) {
  3. println(name)
  4. } else {
  5. println("yc")
  6. }
  7. }
  8. fun check(name: String?) {
  9. println(name ?: "yc")
  10. }

04.安全转换运算符:as?

安全转换运算符:as? 用于把值转换为指定的类型,如果值不适合该类型则返回 null

</>复制代码

  1. fun check(any: Any?) {
  2. val result = any as? String
  3. println(result ?: println("is not String"))
  4. }

05.非空断言:!!

非空断言用于把任何值转换为非空类型,如果对 null 值做非空断言,则会抛出异常

</>复制代码

  1. fun main(args: Array) {
  2. var name: String? = "yc"
  3. check(name) //7
  4. name = null
  5. check(name) //KotlinNullPointerException
  6. }
  7. fun check(name: String?) {
  8. println(name!!.length)
  9. }

06.let函数说明

let 函数可用于在表达式不为 null 时才执行指定代码块

</>复制代码

  1. fun main(args: Array) {
  2. var name: String? = "yc"
  3. check(name) //yc
  4. name = null
  5. check(name) //什么都不会输出
  6. }
  7. fun check(name: String?) {
  8. name?.let {
  9. println(name)
  10. }
  11. }

07.可空类型的扩展

为可空类型定义扩展函数是一种更强大的处理 null 值的方式,可以允许接收者为 null 的调用,并在该函数中处理 null ,而不是在确保变量不为 null 之后再调用它的方法

例如,如下方法可以被正常调用而不会发生空指针异常

</>复制代码

  1. val name: String? = null
  2. println(name.isNullOrEmpty()) //true

isNullOrEmpty() 的方法签名如下所示,可以看到这是为可空类型 CharSequence? 定义的扩展函数,方法中已经处理了方法调用者为 null 的情况

</>复制代码

  1. @kotlin.internal.InlineOnly
  2. public inline fun CharSequence?.isNullOrEmpty(): Boolean {
  3. contract {
  4. returns(false) implies (this@isNullOrEmpty != null)
  5. }
  6. return this == null || this.length == 0
  7. }

08.Java中判断方式 8.1 防御式编程

“防御式编程”大家应该不陌生,核心思想是不信任任何“外部”输入。

不管是真实的用户输入还是其他模块传入的实参,具体点就是各种判空。创建一个方法需要判空,创建一个逻辑块需要判空,甚至自己的代码内部也需要判空(防止对象的回收之类的)。

</>复制代码

  1. public void showToast(Activity activity) {
  2. if (activity == null) {
  3. return;
  4. }
  5. }

8.2 契约式编程

各个模块之间约定好一种规则,大家按照规则来办事,出了问题找没有遵守规则的人负责,这样可以避免大量的判空逻辑。Android 提供了相关的注解以及最基础的检查来协助开发者,示例如下:博客

</>复制代码

  1. public void showToast(@NonNull Activity activity) {
  2. ......
  3. }

给 Activity 增加了 @NonNull 的注解,就是向所有调用这个方法的人声明了一个约定,调用方应该保证传入的 activity 非空。当然聪明的你应该知道,这是一个很弱的限制,调用方没注意或者不理会这个注解的话,程序就依然还有 NPE 导致的 crash 的风险。

09.kotlin是否解决NPE

有些文章说 Kotlin 帮开发者解决了NPE(NullPointerException),这个说法是不对的。Kotlin没有帮开发者解决了NPE,而是通过在语言层面增加各种强规则,强制开发者去自己处理可能的空指针问题,达到尽量减少(只能减少而无法完全避免)出现 NPE 的目的。

10.kotlin如何约束非空判断

声明阶段

变量需要决定自己是否可为空,比如 private var goodsId: String ?= null,这样就是可接受 null

传递阶段

在变量传递阶段,必须保持“可空性”一致,比如形参声明是不为空的,那么实参必须本身是非空或者转为非空才能正常传递。示例如下:

</>复制代码

  1. private var goodsId: String? = null
  2. private fun Main(){
  3. getName(goodsId!!)
  4. }
  5. private fun getName(name : String){
  6. Log.i("", "---$name")
  7. }

还有一种方式,在方法中添加?

</>复制代码

  1. private fun Main(){
  2. getName(goodsId)
  3. }
  4. private fun getName(name : String?){
  5. Log.i("", "---$name")
  6. }

使用阶段

在使用阶段,需要严格判空

</>复制代码

  1. var time: Long? = 1000
  2. private fun Main(){
  3. time!!.toFloat()
  4. time?.toInt()
  5. }

得出结论

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

11.导致NPE的场景 11.1 方法参数声明非空

比如,请求网络接口,需要传递参数,这种情况下每个字段都可能为空,为了增强逻辑,可以在方法参数上加上"?",可以避免后端处理参数值时抛出空指针异常。博客

</>复制代码

  1. /**

</>复制代码

  1. */
  2. @POST("user/login")
  3. fun userLogin(
  4. @Query("username") userName: String?,
  5. @Query("password") password: String?
  6. ): Observable>
  7. ```
11.2 !! 强行转为非空

当将可空类型赋值给非空类型时,需要有对空类型的判断,确保非空才能赋值(Kotlin 的约束)。使用!! 可以很方便得将“可空”转为“非空”,但可空变量值为 null,则会 crash。

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

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

</>复制代码

  1. param?.let {
  2. doSomething(it)
  3. }

想换个工作,渴望同行内推我

个人信息

姓名:杨充【26岁】

邮箱:yangchong211@163.com

微信:13667225184

GitHub:https://github.com/yangchong211

博客汇总:https://github.com/yangchong2...

干活集中营:Android端技术博客和开源项目审核员

目前工作情况:在职状态

技术项目和博客:GitHub项目7k以上star,follower1.1k以上,发表博客100多篇。

热爱技术:开源项目和博客多次被鸿洋,郭霖,Android技术周刊,干活集中营等等推荐。

学历:武汉软件工程职业学院,大专学历

工作年限:3年多

工作地点:北京

关于近期投递简历一点感想

从进入Android这个行业以来,前两次几乎都是朋友内推,面试机会相对容易,都是一个App一个人做或者两个人做,用户相对来说并不多。这次想着离职,主要是想进入一个较大的平台,大概可以理解为Android端有个至少四五人,可以进行技术交流,渴望自己能够在技术上突破,这就像自己平时独自跑步,和跟着一群跑马拉松的人跑步,那种紧张感肯定是不一样的。

近段时间,尝试着向一些较大的公司投递简历,大概在拉钩上投了15个左右(不喜欢海投),发现绝大多数简历到不了技术那里,就被人事说学历不够,经验不够,工作不匹配等情况回绝。不过也可以理解,看简历无非就是学历和经验,貌似自己的履历是差了一点。

这大概是第一次在网上发一个主动希望同行内推的介绍,如果你的公司有Android方面的招聘,能否内推一下我这个小人物,感谢。

关于其他内容介绍 01.关于博客汇总链接

1.技术博客汇总

2.开源项目汇总

3.生活博客汇总

4.喜马拉雅音频汇总

5.其他汇总

02.关于我的博客

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

简书:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜马拉雅听书:http://www.ximalaya.com/zhubo...

开源中国:https://my.oschina.net/zbj161...

泡在网上的日子:http://www.jcodecraeer.com/me...

邮箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault头条:https://segmentfault.com/u/xi...

掘金:https://juejin.im/user/593943...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75129.html

相关文章

  • Kotlin 极简教程 》第4章 基本数据类型与类型系统

    摘要:本章我们来学习一下的基本数据类型与类型系统。字符串就是一个抽象数据类型。如果程序语言的语法中含有类型标记,就称该语言是显式类型化的,否则就称为隐式类型化的。但是,可以把中对应的这几种基本数据类型,理解为的基本类型的装箱类。 第4章 基本数据类型与类型系统 《Kotlin极简教程》正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅读 非常感谢您亲爱的读...

    MoAir 评论0 收藏0
  • 从零开始学 Kotlin 之「2」数据类型

    摘要:前言大家好,这里是从零开始学之数据类型,本文首发于公众号,欢迎前往大家关注。输出布尔类型中的布尔类型用表示,它的值有和。若需要可空引用时,布尔类型的值会被装箱。此时程序会抛出异常最后从零开始学之数据类型到这里就结束了。 前言 大家好,这里是「从零开始学 Kotlin 之『2 』数据类型」,本文首发于公众号「Binguner」,欢迎前往大家关注。我会每周分享一些关于 Android 和...

    Awbeci 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<