Kotlin可空性探索

目录介绍

  • 01.可空性
  • 02.安全调用运算符:?.
  • 03.Elvis运算符:?:
  • 04.安全转换运算符:as?
  • 05.非空断言:!!
  • 06.let函数说明
  • 07.可空类型的扩展
  • 08.Java中判断方式
  • 09.kotlin是否解决NPE
  • 10.kotlin如何约束非空判断
  • 11.致使NPE的场景

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:github.com/yangchong21…
    • 博客汇总:github.com/yangchong21…
    • 干活集中营:Android端技术博客和开源项目审核员
    • 目前工做状况:在职状态
    • 技术项目和博客:GitHub项目7k以上star,follower1.1k以上,发表博客100多篇。
    • 热爱技术:开源项目和博客屡次被鸿洋,郭霖,Android技术周刊,干活集中营等等推荐。
    • 学历:武汉软件工程职业学院,大专学历
    • 工做年限:3年多
    • 工做地点:北京
  • 关于近期投递简历一点感想
    • 从进入Android这个行业以来,前两次几乎都是朋友内推,面试机会相对容易,都是一个App一我的作或者两我的作,用户相对来讲并很少。此次想着离职,主要是想进入一个较大的平台,大概能够理解为Android端有个至少四五人,能够进行技术交流,渴望本身可以在技术上突破,这就像本身平时独自跑步,和跟着一群跑马拉松的人跑步,那种紧张感确定是不同的。
    • 近段时间,尝试着向一些较大的公司投递简历,大概在拉钩上投了15个左右(不喜欢海投),发现绝大多数简历到不了技术那里,就被人事说学历不够,经验不够,工做不匹配等状况回绝。不过也能够理解,看简历无非就是学历和经验,貌似本身的履历是差了一点。
    • 这大概是第一次在网上发一个主动但愿同行内推的介绍,若是你的公司有Android方面的招聘,可否内推一下我这个小人物,感谢。

关于其余内容介绍

01.关于博客汇总连接

02.关于个人博客

相关文章
相关标签/搜索