Kotlin,是由JetBrains开发的一种在Java虚拟机上运行的静态类型编程语言……
关于Kotlin的背景,看到这篇文章的你想必在其他地方已多次看到介绍,这里就不赘述了。
阅前须知:本系列文章需要一定的Java基础知识,并且所举的例子可能会包含些Android上的代码,比较适合之前使用Java从事Android开发的朋友。
下面进入正题。
为什么我推荐使用Kotlin?
JVM 语言
首先,Kotlin可以编译为字节码运行在JVM(在Android中是Dalvik/ART)上,因此它可以与Java之间很好地互相调用。这样带来的好处是你不用担心Kotlin的库不完善,因为你可以直接使用Java中各种成熟的第三方库,同时也使得Kotlin与Java之间的混编很轻松。这是它的天然优势。
语法简练
其次,Kotlin的语法非常简练。举个例子,它的构造方法的写法。假设我们想定义一个Person类,它从服务端返回的JSON解析,所以所有成员变量都是不可变的。我们来看Java的写法:
1 | public class Person { |
再对比一下Kotlin的写法:
1 | class Person(val age: Int, val name: String) |
再看看其他的例子,比如空指针检查,Java代码:
1 | if (park == null || park.code == null) { |
Kotlin:
1 | park?.code ?: return |
一些集合操作:
1 | list.sorted() // 返回排序后的结果 |
还有强大的自动类型推断,没有new
关键字,简洁的when
语句,可省略的分号等等。
空安全
Kotlin在声明变量或函数类型的时候,需要声明是否可空(类型后面加一个问号表示为可空)。当你把null或可能为空的值赋给一个非空类型的变量时,就会编译失败。而当你使用可能为空的变量时,就必须在调用它的函数或成员变量前进行空检查。空检查有两种,一种是使用?
,如果为空,则返回null
,不为空才调用后面的变量或函数,如前面例的空指针检查的例子。一种是使用!!
,进行非空断言,如果这时候为空,则会抛出异常。
扩展函数
举个例子,我们需要一个将dp转为px的方法,如果是用Java你可以会定义一个方法:
1 | public class ScreenUtil { |
然后调用的时候是:
1 | final float width = ScreenUtil.dpToPx(12); |
使用Kotlin,你可以定义一个扩展函数:
1 | fun Float.dpToPx() = //... |
然后你在使用的时候就可以是:
1 | val width = 12f.dpToPx() |
是不是特别的酷?
还有其他特性,比如Lambda表达式,内联函数,协程,操作符重载,类型检查和转换,类型别名等等,就不多介绍了。
使用Kotlin有什么坑?
Kotlin 的缺陷?
我在项目中使用Kotlin大概也有一年了,就Kotlin本身的缺陷而言,几乎没有。
当然也不是说完全没有,目前我一共遇到两个问题,但都不是影响项目开发的问题。这两个问题如下:
第一个问题是,父类定义了一个可以在外部访问,但只能在内部修改的成员变量(见下面代码),如果在子类中访问,那么可能导致混淆时出错。
1 | protected var selectedOption: T? = null |
混淆时会产生如下警告:
1 | can't find referenced method 'void setSelectedOption(java.lang.Object)' in program class 子类名称 |
这个问题也有其他人提出过,见jetbrains官网
如果你需要这样写,可以使用幕后字段,如下:
1 | private var _selectedOption: T? = null |
第二个问题是,无法定义一个成员变量,使得它可以被外部修改但只能被内部访问。比如类似下面的代码:
1 | private var index: Int = 0 |
或者是:
1 | var index: Int = 0 |
它们都是无法编译通过的。
注意事项
目前来看,Kotlin没有什么影响开发的缺陷,但是在使用时还是需要注意和避免一些问题。常见的情况如下:
重写Java类的方法时,原来可能为空的参数的类型应声明为可空类型。比如我们的onActivityResult(int, int, Intent)
方法,可能重写时IDE帮我们生成的代码如下:
1 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { |
上面的data
参数被声明为非空类型,在生成的字节码中,会对它进行非空断言,也就是如果这时候的传过来的data
参数为空,即使你的函数里面没有使用到它,仍然会导致异常。所以应该把它的类型声明为可空类型Intent?
。
另外要注意的就是,Kotlin有一些Java所没有的关键字,但也取消了一些关键字,所以如果想让Kotlin的代码能较好地与Java代码互相调用,应在命名上尽量避免这些关键字。如果是Java中使用到了Kotlin的关键字,那么在Kotlin中加上反引号`
就可以解决。比如`in`
。但如果Kotlin中使用了Java的关键字,那么在Java当中就不好处理了,比如你非得定义一个变量叫做new
……
其他一些与Java之间互相调用要注意的事情,可以参考我之前编译的《Kotlin Java 互通指南》。
上手Kotlin难不难?
对于原来使用Java的人员,Kotlin的学习坡度可谓是相当的低。如果这里的上手指的是可以马上在项目当中使用它开发且不会比使用Java增加更多的时间成本的话,那以我身边的同事来看,上手所花费的时间是半小时到几天不等。
为什么上手会这么轻松?
我觉得主要原因如下:
一是Kotlin可以和Java一样被编译成字节码,所以不用担心编译之后是否有兼容问题或其他问题,并且有前面提到的它与Java的相互调用及混编的优势,所以即使有些地方你不知道用Kotlin怎么写,你还可以用Java来实现,所以可以说没有后顾之忧。
二是在原来使用Java的Android项目中引入Kotlin非常轻松。在Gradle项目中,只需引入Kotlin插件及它的一个库就可以了用Kotlin来写代码了,就像引入一个第三方库一样简单。
三是JetBrains所出的IDEA及基于它的Android Studio对Kotlin的支持非常完美,它的Kotlin插件还提供了将Java代码转为Kotlin的功能。所以,即便你有些代码不知道用Kotlin怎么写,没关系,写成Java代码,再用IDE转为Kotlin代码就可以了。
四是Kotlin本身的语法糖及其所带来的便利性,使得它的开发效率比Java要高上许多,即使偶尔需要查一下语法或写法,所花费的时间也可以被开发上的高效率轻易抵消,并且高效的开发可以让你节省下来更多的时间。
现有的Android项目从Java转向Kotlin有什么坑?
没有坑。
要解决配置问题?如前面所说,就像使用一个第三方库一样简单,只需要添加几行配置,不需要解决什么编译问题,并且IDE对它的支持非常完善,提供了将Java代码转为Kotlin代码的功能。
会导致APK变大很多?引入Kotlin会需要引入它的一个库,目前最新的1.3.11版本,也就1M左右。如果你项目中开启了混淆,则实际增加的大小会小很多。相比起一些第三方组件,这不是你需要担心的问题。
影响编译速度?Kotlin的编译及增量编译都非常的快,和Java差不多,有些时候甚至比Java还快,所以编译时间也大可放心。
学习资料充足么?Kotlin的文档非常完善,学习起来相当方便,即便你在使用时有问题,在google上都可以轻松找到答案。
怕以后不好找其他人维护这个Kotlin项目?相信我,熟悉Java的人,只要去学,几天就能使用它来开发项目。所以不用担心找不到会Kotlin的人,真找不到,找会Java的,让他学习几天不就完了吗?
Android项目引入Kotlin需要添加什么配置?
一共需要两步。注意下面的版本号,应根据你的情况需要进行更新。
第一步,应用插件。在根项目的build.gradle中的buildscript
增加kotlin版本的变量,并且在其下的dependencies
中添加kotlin的gradle插件依赖:
1 | buildscript { |
然后在你的app模块的build.gradle中,添加以下声明:
1 | apply plugin: 'kotlin-android' |
kotlin-android-extensions
顾名思义,是在Android上的一个扩展插件,它可以帮助我们用更少的代码来开发Android。
第二步,添加依赖声明。在app的dependencies中添加以下依赖:
1 | // kotlin standard library |
然后就可以愉快地开始用kotlin开发了。
如果你还有其他疑问,欢迎留言。如果没有问题,那下面我们就——Kotlin,走起吧。