五分钟学会 Kotlin 语法

作者: EitanLiu | 来源:发表于2016-10-08 20:17 被阅读52018次

    为什么使用Kotlin

    项目一期在收尾了终于有时间折腾了,一个多月以来Kotlin从入门到现在,坚持用来开发的切身感受。因为语法与Java的区别挺大的一开始很想放弃,如果不是因为项目在使用,想必很少人会尝试这样一门小众语言,但是习惯后会发现这些年究竟浪费多少时间在写无用的Java代码了,Kotlin在兼容Java的基础上还能大大提升开发效率。Kotlin有许多特性但对于开发来说,快速适应和学习更为重要,很多时候我们都是在不明白其原因就开始使用的,正如我们不可能把Retrofit原理研究透才使用它。只要它足够稳定成熟,并能有效的提升开发效率都是值得尝试的。鄙人不才,目前使用Kotlin的原因主要是因为它语法简洁,支持lambda表达式,强大的when语法,不用写分号结尾,光是这些就足以让我喜欢Kotlin。至于空安全之类的特性,毕竟服务端数据类型太多null了并没多大感触,这些特性在实际应用中潜移默化的就吸收了,以至于现在遇到几个Java编写的代码,都有些不适应了。

    修改说明

    突然火了一脸懵逼,Google IO的影响真是不容小觑。避免误人子弟还是修改下比较好,也就把上一篇文章的基础知识也搬迁过来,对条件判断when还有空判断处理进行了修改,添加了lambda说明,移除过期链接。

    Kotlin 基本语法

    先说个学习Kotlin语法的小窍门,将代码用Java写好,然后Code/Conver Java File to Kotlin File转换成Kotlin代码,或者将Java代码复制到Kotlin文件会提示转换也是挺方便的,比较差异很容易就能理解了,一开始难免不适应习惯后相信你一定会喜欢上Kotlin

    1). 定义

    忘掉Java的那一套写法不然会很不适应的,Kotlin有自己的特性不该被Java的思维所束缚。在Kotlin中常量用val声明,变了用var声明,关键字在前面,类型以冒号:隔开在后面,也可以省略直接赋值,类型后带问号?表示可为空类型(默认空安全)。
    常量val延迟加载by lazy{},默认线程安全关闭线程安全lazy(LazyThreadSafetyMode.NONE){},变量var延迟加载lateinit

    //常量数组int[][][] arrs = new int[3][2][1];
    val arrs = Array(3) { Array(2) { IntArray(1) } }
    //空安全变量
    var str: String = "hello"
    var str1 = "word"
    //可为空字符串变量
    var str2: String? = null
    
    

    2). 条件

    if...else 正常使用,不过移除了switch用更强大的when替代,when子式可以是常量、变量、返回数值的表达式、返回Boolean值的表达式,强大到用来替换if...else if

    // 测试值 x = 0, -1, 1, 2, 3, 6, 10
    var x = 10
    when (x) {
        //常量
        2 -> println("等于2")
        //数值表达式
        if (x > 0) 1 else -1 -> println("大于0并等于1,或小于0并等于-1")
        //Boolean类型表达式
        in 1..5 -> println("范围匹配1-5")
        !in 6..9 -> println("不是6-9")
        is Int -> println("类型判断")
        else -> println("else")
    }
    // 代替if...else if
    when{
        x > 6 && x <= 10  ->  println("大于6小于等于10")
        x < 6 -> println("小于6")
        else -> println("else")
    }
    

    3). 循环

    whiledo...while 同Java并无区别,for则有很大改变并多出了几个变种

    val list = arrayListOf("aa", "bb", "cc")
    //递增for (int i = 0; i < list.size(); i++)
    for (i in list.indices) {
       print(list[i])
    }
    //递增for (int i = 2; i < list.size(); i++)
    for (i in 2..list.size-1) {
       print(list[i])
    }
    //递减for (int i = list.size() - 1; i >= 0; i--)
    for (i in list.size - 1 downTo 0) {
        print(list[i])
    }
    //操作列表内的对象
    for (item in list) {
        print(item)
    }
    //加强版
    for((i, item) in list.witnIndex()) {
        print(list[i])
        print(item)
    }
    //变种版
    list.forEach {
        print(it)
    }
    
    list.forEach {
        print(it)
    }
    
    list.forEachIndexed { i, s ->
        print(list[i])
        print(s)
    }
    
    list.forEachIndexed(object :(Int,String) -> Unit{
        override fun invoke(i: Int, s: String) {
            print(list[i])
            print(s)
        }
    })
    

    万能的冒号

    在Kotlin中冒号:用万能来称呼绝不为过。常量变量的类型声明,函数的返回值,类的继承都需要它

    //val表示常量var表示变量声明
    val name: String = "tutu" 
    //省略类型说明
    var age = "23"
    //fun表示函数
    fun getName(): String{
       return "tutu"
    }
    //类继承
    class UserList<E>(): ArrayList<E>() {
        //...
    }
    
    

    除此之外还有一个特别的地方也需要它,使用Java类的时候。Kotlin最终会还是编译成Java字节码,使用到Java类是必然的,在Kotlin语法如下

    val intent = Intent(this, MainActivity::class.java)
    
    

    类名::class.java没有为什么就这么写记着就是

    我是谁的@

    除了冒号另一个重要符号@,想必用到内部类和匿名内部类的地方一定很多,再加上支持lambda语法,没有它谁告诉你thisreturn指的是哪一个

    class User {
        inner class State{
            fun getUser(): User{
                //返回User
                return this@User
            }
            fun getState(): State{
                //返回State
                return this@State
            }
        }
    }
    
    

    偷懒的方法

    1). Kotlin特色
    Java的getter/setter方法自动转换成属性,对应到Kotlin属性的调用

    public class User {
        private String name;
        private String age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAge() {
            return age;
        }
    
        public void setAge(String age) {
            this.age = age;
        }
    }
    
    

    反之Kotlin的属性自动生成Java的getter/setter方法,方便在Java中调用,同样的定义在Kotlin中

    class User {
        var name: String? = null
        var age: String? = null
    }
    
    

    这样一个Java类在Kotlin中只需这样调用

    val user = User()
    //赋值
    user.name = "tutu"
    user.age = "23"
    //取值
    val name = user.name
    val age = user.age
    
    

    我们的getter/setter方法有时不会这么简单,这就需要自定义getter/setter了,另起一行设置get()/set(value)方法,实现一个Java中常用的单例,这里只为了展示,单例在Kotlin有更简单的方法实现,只要在 package 级别创建一个 object 即可

    class User {
        companion object {
            @Volatile var instance: User? = null
                get() {
                    if (field == null) {
                        synchronized(User::class.java) {
                            if (field == null)
                                field = User()
                        }
                    }
                    return field
                }
        }
    
        var name: String? = null
        var age: String? = null
    }
    
    

    自定义getter/setter重点在field,跟我们熟悉所Java的this指代当前类一样,field指代当前参数,直接使用参数名instance代替不会报错但单例就没效果了

    2). 字符串模板
    在Java中拼接字符串的代码可读性都很差,在Kotlin字符串拼接变得非常简洁,只需用$后面加上参数名,复杂的参数要加上{}

    val user = User()
    //赋值
    user.name = "tutu"
    user.age = "23"
    //取值
    val name = user.name
    val age = user.age
    var userInfo = "name:${user.name},  age:$age"
    //输出结果:name:tutu, age:23
    
    

    3). lambda
    一开始觉得lambda很高级完全看不懂,其实很简单的就是把接口名、方法名和参数类型省掉不写再加个->罢了,明白这点了很好理解。

    // 无参数无返回值
    Thread(Runnable {
        sleep(1000)
    }).start()
    // 单参数不带返回值
    view.setOnClickListener { v ->
        Log.e("tag", "${v.tag}")
    }
    // 多参数带返回值
    view.setOnKeyListener(View.OnKeyListener { v, keyCode, event ->
        Log.e("tag", "keyCode$keyCode, ${event.keyCode}")
        if (event.keyCode == KeyEvent.KEYCODE_BACK)
            return@OnKeyListener true
        false
    })
    

    新面孔

    1). 延迟加载
    2). 流程控制
    内容上一篇写过参考 Android Kotlin 学习笔记,不重复介绍

    空判断

    Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理

    //类型后面加?表示可为空
    var age: String? = "23" 
    //抛出空指针异常
    val ages = age!!.toInt()
    //不做处理返回 null
    val ages1 = age?.toInt()
    //age为空返回-1
    val ages2 = age?.toInt() ?: -1
    
    

    更多空处理NullPointException 利器 Kotlin 可选型

    注意事项

    内部类和参数默认为public,而在Java中为 default 即在同一个包中可见
    类默认为不可继承(final),想要可被继承要声明为openabstract
    取消了static关键字,静态方法和参数统一写在companion object
    internal模块内可见,inner内部类

    以上仅是对使用频率较高的语法总结,学会基本可以阅读Kotlin代码,遇到点问题Google速查一下,至于智能转换、类型推导之类的不用说使用后喜欢自然就会了。当然这只是kotlin的基本语法,方便Java快速熟悉kotlin,深入学习还请阅读相关资料。

    相关链接

    在线学习
    Kotlin 官方文档
    翻译出处kotlin-web-site-cn
    中文站(更新到 1.1):https://www.kotlincn.net/
    网址(更新到 1.0.3):http://tanfujun.com/kotlin-web-site-cn/
    Kotlin 中文论坛:https://www.kotliner.cn/
    《Kotlin for android developers》中文版翻译

    后记

    Kotlin专题

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。转载请保留作者及原文链接

    相关文章

      网友评论

      • 卖炭少年炭治郎:写的 简单 易懂
      • 我好芒://递增for (int i = 2; i < list.size(); i++)
        for (i in 2..list.size-1) {
        print(list[i])
        }
        这里应该是相当于递增for (int i = 2; i < list.size() -1; i++) 吧
        我好芒:@TUTUTOO 哦哦 明白了
        EitanLiu: @wyu_xks 不..代表区间可以理解为<=
      • c173570ac0f9:哈哈哈 一起学习 https://github.com/youxin11544/Kotlin-learning 从java到kotlin,没有一句废话
      • 阿V很简单:我也来报名.今天开始用kotlin
      • 时光青年依旧蓝:这玩儿和TypeScript语法一样,哈哈哈哈哈哈哈哈,我是不是赚了
        EitanLiu:赚到了哈
      • Heymie黑米://递减for (int i = list.size(); i >= 0; i--)
        for (i in list.size downTo 0) {
        print(list[i])
        }
        越界
        EitanLiu:多谢纠正
      • 411ea742de26:感觉很多就是抄scala啊
      • 705dd400c235:android的未来,开起来是少了不少,希望自己有时间赶紧好好研究下。发现现在最缺少的就是时间呢……
      • 9a95bdb72b18:内部类和参数默认为public,而在Java中为default吧
      • RunSnails:和swift语法一毛一样
      • 伟君子:火钳刘明
      • 8084b9a7ab47:我看到说::class.java是映射调用?
      • HaS7:跟scala挺像的
      • 李梦成:除此之外还有一个特别的地方也需要它,使用Java类的时候。Kotlin最终会还是编译成Java字节码,使用到Java类是必然的,在Kotlin语法如下

        val intent = Intent(this, MainActivity::class.java)
        类名::class.java没有为什么就这么写记着就是
        ——————————
        楼主,请问一下,我在java类里面这样写
        Intent intent = new Intent(mActivity, MainActivity.class);
        的时候
        编译报错提醒找不到MainActivity类(MainActivity由.java文件转换为.kt文件后出现此问题)
        怎么解决啊?
        EitanLiu:@而不自知 方法没错,确认下自动转换后的文件有没错误
      • 2e34aa5f193d:来个视频感觉会更爽
      • f66a190500cc:总结的很不错,结合着看官方文档很快就能够理解,谢谢分享
      • chenhan:点赞个
      • 正中同学:有点难理解
      • 耑意儿:赞啊,土土😀
        耑意儿: @小耳朵图图是我 哈😋
        EitanLiu: @傲娇小野猫 被发现了啊
      • 698210a3030f:火钳刘明
      • 698210a3030f:看了一下午,这个作者的文章最易读,适合快速入手:wink:
      • 142dd807b5b4:str ?: return true
        这个 ?: 怎么理解呢@小耳朵图图是我
        EitanLiu:左边内容为空返回右边内容,补充到空处理了
      • 草木皆灰:Kotlin从入门到放弃。。
      • 咦哎:火钳刘明
      • Alien的小窝:群友好,哈哈,我是deeper
        EitanLiu:之前推荐没人学,现在好了不用到处安利
      • 荆人七十:冒号有点像scala
        EitanLiu:@荆人七十 这些新语音都一样Swift也是。
      • 树叶秋:有先见
      • 唧唧叽叽吉吉::smirk: 火钳刘明
      • a372e1185219:学习下
      • Season_zlc:火钳刘明
      • newbiecoder:最近这个帖子应该会被火。。
        EitanLiu:一脸懵逼
      • d698bbfa455a:Kotlin从入门到精通
      • 09d8e043ac44:火前留名
      • 邓小帅:感觉这帐子要火, 先留名, 没错, 我就是邓小帅!:heart_eyes:
        邓小帅:@小耳朵图图是我 因为谷歌刚宣布kotlin为一级开发语言
        EitanLiu:@邓小帅 还以为简书被攻击了
      • 3ecd06b585a6:Android的未来
      • fec66b3ed5ef:学习一下,前排打卡..android未来的语言
      • fendo:赞一个!

      本文标题:五分钟学会 Kotlin 语法

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