空安全之可空、非空类型及其操作符使用

亲自码一遍 可空类型和非空类型 以及 操作符使用规则及其注意点
  • 引入:在Java中 异常 NullPointerException 简称 NPE 空指针异常 也是最常见的异常之一
    // 在KT中,出现NPE现象的原因无非就下面几种:
    // (1). 代码中显示地调用了 throw NullPointerException
    // (2). Java互操作
    // 1. 外部Java代码导致
    // 2. 企图访问平台类型的null引用的成员
    // 3. 用于具有错误可空性的Java互操作,例如List 中添加 null 需要添加可空类型 List俩处理
    // (3). 使用 !! 操作符
    // (4). 对于初始化时,有些数据可能不一致:
    // 1. 如果一个未初始化的this 用在构造函数的某个地方
    // 2. 超类的构造函数中调用一个开放成员,该成员在派生类中实现使用了为初始化的状态
可空类型和非空类型
fun main() {
    // KT 中类型系统区分一个引用是否可容纳null还是不能容纳,例子展示
    // 非空类型只能赋值为非空
    var str1: String;// 使用之前必须赋值,否则编译时异常
    1. println("$str1") // Variable 'str1' must be initialized
    // var str2: String = null // 非空类型不能赋值为不为空 否则提示错误:Null can not be a value of a non-null type String
    var str3: String = "hgz";
    // 如过我们就是要访问可空类型的str4的属性,可以添加可空类型 操作符 ? 就不会编译时异常 返回为null
    var str4: String? = null
    println("$str4") // 返回结果 null 不会报PNE
    // 如果调用可空类型对象的一些函数或者属性 正常调用就会提示下面错误
    // 可空函数的引用需要使用 空安全调用符 或者 非空断言 来修饰 才可以使用 再或者使用显示检测str4是否为null
    // var len = str4.length // 错误提示 Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
    var len1 = str4?.length
    // 或
    //var len2 = str4!!.length// 如果str4为null 运行时异常 NPE java.lang.NullPointerException
    // 或
    var len3 = if (str4 != null) str4.length else -1
    // 简写为
    var len4 = str4?.length ?: -1
    println(len1)
    //println(len2)
    println(len3)
    println(len4)
    //str4 = "hgz"
    // 空安全调用符 ?. 在链式调用中是很有用的 比如
    // 如果链式调用中的任何一个属性(环节)为空,这个链式调用就会返回null
    str4?.length?.let { // 对非空值进行操作
        println("居然有数据")
    }.toString();
    println(str4)
    str4 = "hgz"
    str4?.length.toString();
    println(str4)

    // 对可空数据类型的数据进行操作 比如在可空的集合中,对集合中非空值的数据进行操作,那么安全调用符可以与let一起使用
    var listWithNulls: List = listOf("熳熳", null, "杨杨", "莹莹", null)
    listWithNulls.forEach {
        it?.let {
            // 只操作非空值
            println(it)
        }
    }
    // 打印返回值:熳熳 杨杨 莹莹

    // 还有一点注意:安全调用符也可以出现在赋值的左侧 personal?.user?.name = "小黄"

    // Elvis操作符 相当于java中的三目运算符
    // 操作符:?:
    var name: String? = null// 可空类型
    //var name: String? = "小黄"// 非空类型
    var nameLen = name?.length ?: -1
    println(nameLen)
    // 上述可空的引用name,如果想让它为null的时候返回某一个非空的值(-1),不为空时返回自身某一个属性值(length)
    // 操作符理解 ?: 左侧的表达式非空 就返回 ?: 左侧的表达式值 ,否则返回 ?: 右侧的表达式值
    // 注意:只有 ?: 操作符 左侧表达式为空的时 才会对右侧的表达式求值


    // 非空断言 操作符 !!
    // 非空断言操作符 将任何值转换为非空类型 如若该值为空 就会抛出PNE异常
    var sex: String? = null
    try {
        println(sex!!) // 异常 java.lang.NullPointerException
    } catch (e: NullPointerException) {
        // 需要自己手动处理异常
        sex = "男"
        println("默认值:$sex")
    }

    // 安全类型转换
    val a: String = "1"
    // 如若对象不是目标,类型转换异常抛出
    // val aInt:Int = a as Int // 错误提示 java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    // 如若想避免异常,可以使用安全的类型转换 as?
    val aInt: Int? = a as? Int // 返回值为 null
    println(aInt)

    // 可空类型的集合
    var listStr: List = listOf("蛋蛋", "二蛋", null, "小花", "小芳", null, "小智")
    // 怎样获取上述可空集合的非空值并以集合类型返回 可以通过 filterNotNull() 函数实现
    var nonNullList: List = listStr.filterNotNull();
    nonNullList.forEach { i ->
        println(i)
    }
}

总结:

  1. 非空类型只能赋值为非空
  2. 变量使用之前必须赋值,否则编译时异常
  3. 如果变量赋值为空 需要添加可空操作符 ?
  4. 如果调用可空类型对象的一些函数或者属性 正常调用就会提示下面错误
    错误提示 Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
  5. 可空函数的引用需要使用 空安全调用符 或者 非空断言 来修饰 才可以使用 再或者使用显示检测str4是否为null
  6. 空安全调用符 ?. 在链式调用中是很有用的,如果链式调用中的任何一个属性(环节)为空,这个链式调用就会返回null
  7. 对可空数据类型的数据进行操作 比如在可空的集合中,对集合中非空值的数据进行操作,那么安全调用符可以与let一起使用
  8. 安全调用符也可以出现在赋值的左侧 personal?.user?.name = "小黄"
  9. Elvis操作符 ?: 相当于java中的三目运算符
    操作符理解 ?: 左侧的表达式非空 就返回 ?: 左侧的表达式值 ,否则返回 ?: 右侧的表达式值
    只有 ?: 操作符 左侧表达式为空的时 才会对右侧的表达式求值
  10. 非空断言操作符 将任何值转换为非空类型 如若该值为空 就会抛出PNE异常 异常需要自己手动处理
  11. 安全类型转换 如若对象不是目标类型,类型转换异常抛出 ClassCastException
    如若想避免异常,可以使用安全的类型转换 as?
  12. 可空类型的集合 获取非空值的数据并且以集合形式返回 可以通过 filterNotNull() 函数实现

谢谢亲们的关注支持 记得点赞哦!

你可能感兴趣的:(空安全之可空、非空类型及其操作符使用)