Google 2017 IO大会宣布 Kotlin
作为 Android
一级开发语言,一时间各大技术博客网站,微信订阅号,朋友圈都被 Kotlin
刷屏了,全都是对 Kotlin
的简要介绍,现在过了大约一周感觉大家慢慢平静下来了,发布的文章的质量也更高,更有针对性,相信不久的将来再广大开发者的推动下,Kotlin
会发展的越来越好。
就像 Google
发布 Android
专用的开发工具 AndroidStudio
一样,仅仅一年多的时间,Eclipse
和 Idea
在 Android
开发领域就被完全取代了,Google
的决心是看得见的。Kotlin
能够与 Java
无缝兼容,性能更好,语法更优雅,又有类型推断,函数式编程等新特性支持,相信在 Android
开发领域,取代Java
只是时间问题,毕竟是官网支持的。
本文是对 Kotlin
的第一次接触,重点放在项目搭建和新特性的体验上,更深的细节将会放在后面的文章中研究,go ~
推荐文章
Kotlin
官网和对应中文版,这个中文版文档的风格和官网风格一样,对比看起来舒服一点,推荐。
Kotlin
的两篇推荐文章,很早就在推荐使用了
另外备注几份参考文档,各有优势,作补充用
kotlin官网文档中文版 / https://hltj.gitbooks.io
< kotlin for andriod developer> 中文翻译版 / https://wangjiegulu.gitbooks.io
基本配置
AS 3.0 已经自带了Kotlin的配置,本文在 AS 2.3 基础上进行配置。
打开Setting -> plugin下载插件,重启AS,创建项目 -> new File -> Kotlin Activity,会提示配置相关信息,点击配置即可,插件会在工程中作下面的相关配置,以上可以使用IDE很快完成,整体项目没有很大变化。
project/build.gradle
文件
1 | buildscript { |
app/build.gradle
文件
1 |
|
汇总一些细节
Kotlin
不强制在每句代码后面加;
。Kotlin
不支持三目运算符了,可以使用if(condition) 表达式1 else 表达式2
的方式代替,比如val a = if(b>0) 100 else 0
不再使用
new
关键字创建对象,而是更简单的val user = User()
与
Java
相反,Kotlin
中所有类和方法都默认是不允许继承的,也就是final
的,如果想要继承类或重写方法可以使用open
关键字。Kotlin
中类名不必与文件同名,函数也不是必须声明在类中才可以,可以直接声明在文件中。Kotlin
中注释允许嵌套。使用
is
代替instanceof
,如if(str is String){...}
引用xml中的控件
再也不用 findViewById()
也不用 ButterKnife
注解啦.
这种扩展在性能上和 findViewById()
是一样的,另外需要注意的是,使用这种扩展必须要在 layout
被设置好了才能使用, 在 fragment
里面, 要等到 onViewCreated()
之后才能使用.
1 | <!--在xml定义,id为 mTestTv --> |
空值安全(Null Safety)
Kotlin
是一种空值安全的语言,他基本能帮助你告别 NPE
,并且提供了大量的操作符简化判空操作,更多内容将在下一篇文章<常量变量篇>中详细介绍。
一个使用 safe calls
简化调用的实例
1 | val myParam1:Student? = null |
字符串模版
再也不用 +
或者 StringBuilder
来回拼接和计算字符串,kotlin提供了更加优雅的实现方式。
使用 ${表达式}
的方式可以在字符串中间插入数据。只有一个简单值时可以省略 {}
,同时也支持复杂表达式的计算。
1 | val user = User() |
扩展函数和属性
Kotlin
提供了向一个类扩展新功能的能力,而且不必从这个类继承, 也不必使用任何设计模式, 比如 Decorator
模式之类。 这种功能是通过一种特殊的声明来实现的, Kotlin
中称为 扩展(extension)
。 Kotlin
支持 扩展函数(extension function)
和 扩展属性(extension property)
。
另外我刚开始看这个地方的时候,是将扩展函数声明在使用它的类中,在另一个类中要使用就无法引用了,难道每次都要重新写?那不是很鸡肋。其实由于 java
的惯性,我觉得所有的方法必须声明在类中,java
中确实是这样的, 但是 Kotlin
不必这样做,你的类文件的名字可以不和文件名相同,函数也可以直接声明在文件中,而不是某个类中。
注意:不需要声明
class
,扩展方法和属性是静态加载的, 直接写在.kt
文件中即可。注意:在扩展属性的
get()
方法中不要访问该属性,因为你一旦访问该属性,就会调用get()
方法,从而造成堆栈溢出。
新建 ContextExtensions.kt
文件,在里面声明该扩展函数和扩展属性
1 | // 扩展函数 |
接下来就可以在任何 Context
的实现类,比如 Activity
中使用 logError()
函数和 extensionProperty
属性
1 | // 扩展函数 |
自动类型推断
Kotlin支持自动的类型推断,比如我们可以如下声明一个常量,那么常量 myStr
的类型被推断为 String
类型。可以使用 String
的API。
1 | val myStr = "" |
当进行显示类型转换时,自动进行类型推断,下面声明了两个类,Student
继承自 User
,在 stuUser is Student
的判断之后,stuUser
的类型被推断为 Student
,因此可以直接访问 myClass
属性。
1 | open class User(val name: String, val age: Int) { |
支持 lambda 表达式
使用 lambda 表达式可以使代码更加清晰,原来一层一层的 {}
都被省略掉了,不可否认的是可读性要比原来差一点,不过习惯了就好多了。
另外 Kotlin 也为 lambda 表达式提供了很多扩展支持,来强化 lambda 表达式的使用,在kotlin中,如果函数的最后一个参数是函数,那么这个参数可以直接写在圆括号外面(要用花括号),如果只有一个函数参数,可以直接省略圆括号!而且当参数只有一个时可以省略参数而使用 it
来代替。
1 | mTestTv.setOnClickListener { |
函数是一等公民
函数是一等公民指的是函数和对象,基本数据类型一样,可以作为变量,可以作为参数传递,可以作为返回值。 函数不依赖于类,可以独立存在。
Kotlin支持函数式编程。函数声明的方式为 (参数名:参数类型...)-> 返回值类型
,比如 (param:String)->Int
,指的是一个参数为 String
类型,返回值是 Int
类型的函数,如果没有返回值则使用 Unit
关键字。
刚开始尝试像使用变量一样使用函数,有些不太适应,当你需要将函数进行传递赋值时,先写一个 {}
,将函数声明在 {}
中即可;
尝试简单声明函数
1 | fun myFun(param: String): Int { |
函数作为变量
1 | // 函数作为变量 |
函数作为参数,下面的函数接受一个参数为 String
返回值为 Int
的函数作为参数,并调用他。lis
是形参,(String) -> Int)
是函数类型。下面的两个重载函数的例子,是为了展示只有一个函数参数时的简化写法,多个参数时使用常规写法。结合上面 lambda
表达式的相关用法。
1 | // 只有一个函数做参数,并且只有一个参数 |
函数作为返回值
1 | // 函数作为返回值 |
单表达式函数,当函数的返回值只有一个简单表达式时,可以使用单表达式函数,简化代码
1 | // 单表达式函数 |
数据类
我们经常会创建一些数据类, 什么功能也没有, 而仅仅用来保存数据. 在这些类中, 某些常见的功能经常可以由类中保存的数据内容即可自动推断得到. 在 Kotlin
中, 我们将这样的类称为 数据类, 通过 data
关键字标记;
定义一个数据类,只需要一行代码即可,{}
可以省略掉,数据类会默认生成 equals()
,toString()
, copy()
等方法,这里特别提一下 copy()
,可以生成一个新的数据,这个特性是相当不错的。
当然数据类也有很多限制
主构造器至少要有一个参数;
主构造器的所有参数必须标记为 val 或 var;
数据类不能是abstract类, open 类, 封闭(sealed)类, 或内部(inner)类;
数据类不能继承自任何其他类(但可以实现接口).
1 | data class DataModel(val param1: String, val param2: Int) |
数据类添加成员方法
1 | data class DataModel(val param1: String, val param2: Int) { |