Kotlin 中的判空操作 Elvis 操作符使用踩坑

Kotlin 作为一门有着所谓空安全特性的(年轻)编程语言,有时出于实际业务场景需要还是会把变量声明成可空(Null-able)的,好在由于空安全特性,编译器会强制我们对可空变量进行判空检查(除非你使用了非空断言 !! 强制让编译器闭嘴)。Kotlin 以完全兼容 Java 为设计原则,设计者们该是在设计阶段就预见到了使用者们可能还是需要进行很多判空检查,于是引入了非常简洁优雅的 Elvis 操作符,请看代码:

Java 典型判空操作:

/**
     * <p>控制台打印字符串的长度是多少</>
     * @param str:给定的字符串
     */
    public void askStringLength(String str){
        int i;
        //Java 中我们一般这样判空,或者使用那个三目运算符
        if (str == null){
            i = 0;
        } else{
            i = str.length();
        }

        //或者使用三目运算符
        i = str == null? 0 : str.length();

        System.out.println("The length is " + i);
    }

如上,Java 没有所谓空安全特性。你可能需要写大量上面那样的判空模板代码,而且你肯定无法在每一个变量可能为空的地方加上这种防御性代码,毕竟项目里很容易积攒到成千上万的变量,给这么多变量写上防御性代码想想都头大!当然对于很大概率会抛出空指针异常的地方编译器会做高亮提示,但会给出提示的地方放之整个项目而言实在微不足道。我们手动 new 出来的对象和 null,作为有着完全不同行为的两种实体居然可以赋值给同一个变量,如此,如果在该判空的地方没做判空,就是一个在运行时可能会抛出 NPE(NullPointerException) 的bug!

Kotlin 重新设计了一套完全不同于 Java 的类型系统,声称可大大较少项目中的 NullPointerExceptio(Kotlin因以完全兼容 Java 为设计原则,因而无法完全杜绝 NPE)。就我本人经验看来,效果还不赖,使用 Koltin 项目中的 NPE 确实少多了。而且 Koltin 中对可能抛出 NPE 的地方做判空检查的方式比之 Java 而言实在优雅,从此远离那些烦人的 if-else,只需借助所谓 Elvis 操作符。

关于 Kotlin 的类型系统与 Java 之异同非本文重点,重点是在 Kotlin 中,如果一个变量是可空的,你在访问此变量时如果不做判空检查是通不过编译的(除非你使用了非空断言 !! 强制让编译器闭嘴)!如此使得我们的代码在运行时抛出 NPE 的概率大大减少!嗯能在编译阶段发现的问题就别留到运行时再发现!下面我们直接看看上面包含判空操作的 Java 代码其等价的 Koltin 代码是怎么样的。

Kotlin 典型判空操作:

/**
     *
     * <p>控制台打印字符串的长度是多少</>
     * @param str:给定的字符串
     */
    fun askStringLength(str: String?) {
        val i: Int
        // Kotlin 中我们一般这样对变量判空
        // ?. 是 Kotlin 中所谓的安全调用操作符
        // 如果 str 非空,就返回 str.length,否则返回 null,表达式(str?.length)返回的类型是 Int?   嗯有可能为 null
        // ?; 就是所谓的 Elvis 操作符
        // 如果 ?: 左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式
        i = str?.length?:0//str.length 这么写是通不过编译的
        // 一路流式操作下来是不是感觉很顺畅,那可比 if-else 舒服多了!注意 Kotlin 中的 Elvis 操作符不是三目操作符,Kotlin 中是不存在三木操作符的

        println("The length is $i")
    }

Kotlin 中我们一般这样对变量判空:

i = str?.length?:0

?. 是 Kotlin 中所谓的安全调用操作符,如果 str 非空,就返回 str.length,否则返回 null,表达式(str?.length)返回的类型是 Int? , 嗯有可能为 null,?; 就是所谓的 Elvis 操作符,如果 ?: 左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式(做默认值)。

此时如果我们有了新需求,要求计算一个 List 中所有字符串的长度之和,你很可能会这么写:

/**
     *<p>控制台打印列表中所有字符串长度之和</>
     * @param strings:给定的字符串列表
     */
    fun askStringLength(strings: List<String?>) {
        var i: Int = 0
        strings.forEach { str ->
            i = str?.length?:0 + i //注意这行代码,当然你更可能写成 i += str?.length?:0,为了说明问题先按我写的来
        }
        println("The length is $i")
    }

如果真像上面那样写了,那你肯定得不到正确的结果!你可以运行试试!

原因在于 Elvis 操作符的优先级较低,请看下方我从 Kotlin 官网扒来的操作符优先级表:

Precedence Title Symbols
Highest Postfix ++, --, ., ?., ?
Prefix -, +, ++, --, !, label
Type RHS :, as, as?
Multiplicative *, /, %
Additive +, -
Range ..
Infix function simpleIdentifier
Elvis ?:
Named checks in, !in, is, !is
Comparison <, >, <=, >=
Equality ==, !==
Conjunction &&
Disjunction ` `
Lowest Assignment =, +=, -=, *=, /=, %=

注意 Elvis 操作符的位置!

这行代码:

i = str?.length?:0 + i

其实等价于

i = str?.length ?: (0 + i)

所以想让代码正确运行我们其实应该写成这样:

i = (str?.length?:0) + i

使用时千万要注意操作符的优先级!

完。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280