[Kotlin Tutorials 2] 空安全: Kotlin

作者: 圣骑士wind | 来源:发表于2019-12-30 13:49 被阅读0次

    空安全: Kotlin的一大卖点

    本文收录于: https://github.com/mengdd/KotlinTutorials

    Kotlin的type system旨在减少NullPointerException(NPE).

    主要是通过编译期间, 就区分了哪些东西是不会为null的, 哪些是可能为null的.
    如果想要把null传递给不能为null的类型, 会有编译错误.
    可能为null的引用使用时必须要做相应的检查.

    var a: String = "abc"
    // a = null // compile error
    val aLength = a.length
    
    var b: String? = "abc"
    b = null // ok
    // val bLength = b.length // 不能直接使用, compile error
    

    检查是否为null

    对于可能为null的类型, 可以用if来做显式的检查.
    但是这种只适用于变量不可变的情形, 免得刚检查完是否为null, 它就变了.

    Safe Calls

    可以用操作符?.来进行安全操作.

    var b: String? = "abc"
    val bLength = b?.length // 如果b不为null, 返回长度, 如果b为null, 返回null
    

    上面bLength类型为Int?.

    Safe calls在链式操作时非常有用.
    比如:

    bob?.department?.head?.name
    

    其中任何一个环节为null了最后的结果就为null.

    还可以用在表达式的左边:

    // If either `person` or `person.department` is null, the function is not called:
    person?.department?.head = managersPool.getManager()
    

    let()

    实践中比较常见的是用let()操作符, 对非null的值做一些操作:

    val listWithNulls: List<String?> = listOf("Kotlin", null)
    for (item in listWithNulls) {
        item?.let { println(it) } // prints A and ignores null
    }
    

    Elvis Operator

    我们可能有这样的需求, 有个可能为null的变量, 我们需要在其不为null的时候返回一个表达式, 为null的时候返回一个特定的值.

    比如:

    val l: Int = if (b != null) b.length else -1
    

    我们可以写成这样:

    val l = b?.length ?: -1
    

    仅当?:左边为null的时候, 右边的表达式才会执行.

    实际应用:
    在Kotlin中, return和throw都是表达式, 所以我们可以这样用:

    fun foo(node: Node): String? {
        val parent = node.getParent() ?: return null
        val name = node.getName() ?: throw IllegalArgumentException("name expected")
        // ...
    }
    

    操作符!!

    !!操作符表达的是: "嘿, 肯定不为null".
    所以它称作not-null assertion operator.
    它的作用是把原来可能为null的类型强转成不能为null的类型.

    如果这种断言失败了, 就抛出NPE了.

    仍然可能会遇到NPE的情形

    • throw NullPointerException().
    • !!使用在了为null的对象上.
    • 初始化相关的一些数据不一致情形.
      • 一个构造中没有初始化的this传递到其他地方使用.
      • 基类的构造中使用了open的成员, 实现在子类中, 此时可能还没有被初始化.
    • 和Java互相调用的时候:
      • Java声明的类型叫platform type, 其null安全和Java中的一样.
      • 和Java互相调用时的泛型使用了错误的类型. 比如Kotlin中的MutableList<String>, 在Java代码中可能加入一个null. 此时应该声明为MutableList<String?>.
      • 其他外部Java代码导致的情形.

    相关应用

    安全强转

    强转时如果类型不匹配会抛出ClassCastException
    可以用as?来做安全强转, 当类型不匹配的时候返回null, 而不是抛出异常.

    val aInt: Int? = a as? Int
    

    类型检查用关键字is.

    集合过滤

    集合中有个filterNotNull()可以用来过滤出非空元素.

    val nullableList: List<Int?> = listOf(1, 2, null, 4)
    val intList: List<Int> = nullableList.filterNotNull()
    

    参考资料

    相关文章

      网友评论

        本文标题:[Kotlin Tutorials 2] 空安全: Kotlin

        本文链接:https://www.haomeiwen.com/subject/lkfmoctx.html