Kotlin 语法上的一些亮眼操作

Kotlin 语法上的一些亮眼操作

本文原创,转载请注明出处。
欢迎关注我的 简书 ,关注我的专题 Android Class 我会长期坚持为大家收录简书上高质量的 Android 相关博文。

Kotlin 初体验

写在前面:
上上周我们创建了第一个 kotlin 的 android 应用。上周我花了一周的时间,在工作之余了解了 kotlin 的语法。感叹 kotlin 做为“高级”语言与 java相比,展现出来的简洁、高效、智能。不过如果有人问我 kotlin 和 java 的具体区别,那我肯定会首先描述为 命令式编程语言函数式编程语言 的区别。

命令式编程语言函数式编程语言 用概念描述,可以为:命令式编程语言泛指所有把修改变量的值当作最基本计算方式的语言,函数式编程语言指把一个程序的输出定义为其输入的数学函数的语言,纯函数式编程没有内部状态的概念,也没有副作用。

对两者而言,我的体会并不深刻,所以来引用知乎的一段话:

纯函数式编程语言中的变量也不是命令式编程语言中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称。变量的值是不可变的(immutable),也就是说不允许像命令式编程语言中那样多次给一个变量赋值。比如说在命令式编程语言我们写“x = x + 1”,这依赖可变状态的事实,拿给程序员看说是对的,但拿给数学家看,却被认为这个等式为假。

函数式语言的如条件语句,循环语句也不是命令式编程语言中的控制语句,而是函数的语法糖,比如在Scala语言中,if else不是语句而是三元运算符,是有返回值的。

关于二者的比较可以进一步查阅资料来了解,对于理解编程语言的本质和计算机的构成,很有帮助。

下面我们就来看看与 java 相比,kotlin 有哪些“高级”的语法。

函数扩展

        val array: Array<Int> = arrayOf(4, 5, 6)
        val array3: Array<Int> = arrayOf(7, 8, 9)
        // 声明一个函数扩展,我们需要在函数前加一个接收者类型作为前缀。上面就是为 `Array<Int>` 添加一个 swap 函数
        fun Array<Int>.swap(x: Int, y: Int) {
            // 在扩展函数中的 this 关键字对应接收者对象。
            val temp: Int = this[x]
            this[x] = this[y]
            this[y] = temp
        }
        // 可以在任何 Array<Int> 实例中使用这个函数了
        array.swap(1, 2)
        array3.swap(0, 3)

如果用 java 来做的话,我们需要继承父类。或者用一个方法做这个操作,需要将 array 作为参数传递进去,这样一来就加大了出错概率,也不够自由美观,这就是扩展带来的好处。

空安全

导致 java 程序崩溃最多的 Exception 就是 NullPointerException 也叫 NPE,Kotlin 类型系统致力与消灭它。

在 Kotlin 类型系统中可以为空和不可为空的引用是不同的。比如,普通的 String 类型的变量不能为空:

        var s: String = "activity"
        s = null //编译报错 普通字符串类型不可为空
        
        var t:String? = "fragment"
        t = null //同?声明的 String 可以为空
        
        print(s.length)// 可以调用,这里的 s 永不为 null
        print(t.length)// 报错,这里的 t 可能为空

可以看到,这里在声明一些可能为 null 的引用时,kotlin 是区分对待的,并且在调用的时候自动判断它是否可能为 null,当可能为空的时候,直接用 . 调用,会直接报错。

如果我们想调用,可以用条件判断的方式:

        val u = if (t != null && t.length > 0) {
            print(t.length)
            t.length
        } else {
            -1
        }

这样显然稍显啰嗦,kotlin 自然想到了这一点,这样安全操作符 ?. 就出现了。

        val r: Int? = t?.length

这个表达式,当 t 为 null 时,返回 null,否则返回 t.length

安全调用在链式调用是是很有用的。比如,如果 Bob 是一个雇员可能分配部门(也可能不分配),如果我们想获取 Bob 的部门名作为名字的前缀,就可以这样做:

    bob?.department?.head?.name //这样的调用链在任何一个属性为空都会返回空

如果用 java 来做,那就会完全体现 java 的“又臭又长”了

Elvis 操作符
?: Elvis 操作符表达的是,当左边表达式为空时,会执行右边的表达式。否则执行左边的表达式。

        val o = t?.length ?: -1
        val i = t?.length ?: throw NullPointerException()

!! 表达式

        val y = t!!.length

当 t 为 null 时,抛出一个 NPE,否则返回 t 的长度值。

智能转换

is !is 表达式

    fun smartCast(any: Any) {
        if (any is String) {
            println(any.length)// x is automatically cast to String
        }
    }

通过 is 关键字,在 if 表达式中,any 已经自动被转换成了 String 类型。

安全转换 as?

        val s: String? = any as? String

若 any 为 null 时,显然是不可以转换成 String 的,这时候用 as? 安全转换,如果失败了,则返回 null。

字符串模板

        val firstName = "Android"

        val lastName = "Studio"

        println("his name is $firstName $lastName")

如上所示,kotlin 可以用 $ 将一些值直接连接在字符串当中

单例模式

在 java 中,我们创建一个单例模式的对象可能是这样子的:

public class Utils {

    private Utils() { 
      // This utility class is not publicly instantiable 
    }
    
    public static int getScore(int value) {
        return 2 * value;
    }
    
}

在 kotlin 中,就方便了很多:

object Utils {

    fun getScore(value: Int): Int {
        return 2 * value
    }

}

Bean 对象

在 java 中创建一个 bean 对象,可能是这样的:

public class Developer {

    private String name;
    private int age;

    public Developer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Developer developer = (Developer) o;

        if (age != developer.age) return false;
        return name != null ? name.equals(developer.name) : developer.name == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Developer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在 kotlin 中,可以使用 data 关键字,直接创建一个 bean 对象:

data class Developer(var name: String, var age: Int)

Ranges

kotlin 还有一些特有的属性,比如类型的推断啊,一级构造函数啊,等等。这些自己去撸文档就可以了,最后一个想说的就是 kotlin 中的 Ranges 属性。

Ranges 操作符是由 in 关键字实现的:

if (i in 1..10) {
    println(i) // 打印 1 - 10 闭区间
}

if (x !in 1.0..3.0) println(x)

if (str in "island".."isle") println(str)

当然还有更多的用法和关键字,根据打印值体会:

for (i in 1..4 step 2) print(i) // prints "13"

for (i in 4 downTo 1 step 2) print(i) // prints "42"

for (i in 1.0..2.0 step 0.3) print("$i ") // prints "1.0 1.3 1.6 1.9 "

好了本文对 kotlin 一些我认为很亮眼的语法和用法就介绍完成了,下一步我打算研究下 kotlin 在快速开发 android 上,有哪些黑科技。

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

推荐阅读更多精彩内容