Kotlin可空性探索

栏目: Android · 发布时间: 6年前

内容简介:用)。 例如,String 类型的常规变量不能指向 null

目录介绍

  • 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

var name: String = "yc"
//编译错误
//name = null
  • 如果希望一个变量可以储存 null 引用,需要显式地在类型名称后面加上问好来标记它:

    var name: String? = "yc"
    name = null
  • 问号可以加在任何类型的后面来表示这个类型的变量可以存储 null 引用:Int?、Doubld? 、Long? 等
  • Kotlin 对可空类型的显式支持有助于防止 NullPointerException 导致的异常问题,编译器不允许不对可空变量做 null 检查就直接调用其属性

    fun check(name: String?): Boolean {
        //编译器不允许不对 name 做 null 检查就直接调用其属性
        return name.isNotEmpty()
    }
  • 需要显式地进行 null 检查

    fun check(name: String?): Boolean {
        if (name != null) {
            return name.isNotEmpty()
        }
        return false
    }

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

  • 安全调用运算符:?.

    • 允许把一次 null 检查和一次方法调用合并为一个操作,如果变量值非空,则方法或属性会被调用,否则直接返回 null
  • 例如,以下两种写法是完全等同的:

    fun check(name: String?) {
        if (name != null) {
            println(name.toUpperCase())
        } else {
            println(null)
        }
    }
    
    fun check(name: String?) {
        println(name?.toUpperCase())
    }

03.Elvis运算符:?:

  • Elvis 运算符:?:

    • 用于替代 ?. 直接返回默认值 null 的情况,Elvis 运算符接收两个运算数,如果第一个运算数不为 null ,运算结果就是其运算结果值,如果第一个运算数为 null ,运算结果就是第二个运算数
  • 例如,以下两种写法是完全等同的:

    fun check(name: String?) {
        if (name != null) {
            println(name)
        } else {
            println("yc")
        }
    }
    
    fun check(name: String?) {
        println(name ?: "yc")
    }

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

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

    fun check(any: Any?) {
        val result = any as? String
        println(result ?: println("is not String"))
    }

05.非空断言:!!

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

    fun main(args: Array<String>) {
        var name: String? = "yc"
        check(name) //7
    
        name = null
        check(name) //KotlinNullPointerException
    }
    
    fun check(name: String?) {
        println(name!!.length)
    }

06.let函数说明

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

    fun main(args: Array<String>) {
        var name: String? = "yc"
        check(name) //yc
    
        name = null
        check(name) //什么都不会输出
    }
    
    fun check(name: String?) {
        name?.let {
            println(name)
        }
    }

07.可空类型的扩展

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

    • 例如,如下方法可以被正常调用而不会发生空指针异常
    val name: String? = null
    println(name.isNullOrEmpty()) //true
    • isNullOrEmpty() 的方法签名如下所示,可以看到这是为可空类型 CharSequence? 定义的扩展函数,方法中已经处理了方法调用者为 null 的情况
    @kotlin.internal.InlineOnly
    public inline fun CharSequence?.isNullOrEmpty(): Boolean {
        contract {
            returns(false) implies (this@isNullOrEmpty != null)
        }
    
        return this == null || this.length == 0
    }

08.Java中判断方式

8.1 防御式编程

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

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

8.2 契约式编程

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

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

09.kotlin是否解决NPE

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

10.kotlin如何约束非空判断

  • 声明阶段

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

    • 在变量传递阶段,必须保持“可空性”一致,比如形参声明是不为空的,那么实参必须本身是非空或者转为非空才能正常传递。示例如下:
    private var goodsId: String? = null
    private fun Main(){
        getName(goodsId!!)
    }
    
    private fun getName(name : String){
        Log.i("", "---$name")
    }
    • 还有一种方式,在方法中添加?
    private fun Main(){
        getName(goodsId)
    }
    
    private fun getName(name : String?){
        Log.i("", "---$name")
    }
  • 使用阶段

    • 在使用阶段,需要严格判空
    var time: Long? = 1000
    
    private fun Main(){
        time!!.toFloat()
        time?.toInt()
    }
  • 得出结论

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

11.导致NPE的场景

11.1 方法参数声明非空

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

    /**
*/
@POST("user/login")
fun userLogin(
        @Query("username") userName: String?,
        @Query("password") password: String?
): Observable<ResponseBean<LoginBean>>
```

11.2 !! 强行转为非空

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

    • 因此使用上建议在确保非空时才用 !!: param!!
    • 否则还是尽量放在判空代码块里:
    param?.let {
       doSomething(it)
    }

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

  • 个人信息

    • 姓名:杨充【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.关于博客汇总链接


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Introduction to Programming in Java

Introduction to Programming in Java

Robert Sedgewick、Kevin Wayne / Addison-Wesley / 2007-7-27 / USD 89.00

By emphasizing the application of computer programming not only in success stories in the software industry but also in familiar scenarios in physical and biological science, engineering, and appli......一起来看看 《Introduction to Programming in Java》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具