0. 背景
Kotlin 已经成为了Android 官方支持的语言了,目前像 androidx
里面的库,基本都已经对kotlin有了支持,而且从官方的姿态来看,以后kotlin才会是主流,而java由于一些历史和法务的原因,将在Android的平台上浅浅被Kotlin取代。
本文中,将从一个Android开发者
的角度,来聊一聊Kotlin相对于Java有哪些很不错的特性,当然也有它的缺点,希望大家可以取其精华。
1. Kotlin 的优点
这一章节中,将介绍下Kotlin相对Java的一些优点,也是一些在平时开发中使用比较频繁的功能点。有一些是Kotlin从其他现代语言中借鉴的优点特性,有一些是语法糖,不过都是一些很不多的优点。
1. 空安全
Kotlin 对自己的语言设计很自豪的一个特性,就是“空安全”,声称可以避免大部分的Java里面的NullPointerException。
Kotlin中的空安全总的来说有以下几个方面:
- 可空的类型声明:在声明一个遍历的时候,必须要指定它是否是可以为空的,可以为空和不可以为空将会是按照不同的类型处理,比如
String
和String?
是不同的类型; - 可空类型的访问:在有了可空类型的声明之后,对变量的使用也加上了判断,对于
可空
的类型必须有判空或者使用安全访问(?.的语法)
空安全特性在实际使用中确实能带来很大的好处,能够在语言层面强制要求开发者对所有的可能为空的变量进行处理。
|
|
2. 强制 setter 和 getter
熟悉Java的同学,一定知道Java的规范写法中会提倡使用 setter
和 getter
的写法,而不是直接对熟悉进行访问。这样做的好处就不赘述了。只是这样写的话,会带来很多的样板代码,会在项目中出现大量的 setXXX
和 getXXX
样式的代码。而Kotlin则是直接在语法层面解决了这个问题。
Kotlin中把对熟悉的访问强制使用setter 和 getter,那怕看起来像是直接读取一个成员变量,其实本质上还是访问的它的 getter 方法。这样就直接封死了直接操作成员变量的路。
这样就能完美避免很多 setXXX
和 getXXX
的方法了,需要一个属性,“直接访问“就是了
|
|
3. 强大的 when 表达式
Java中逻辑分支的执行有if else
和 switch
这样的语法支持,在Kotlin 里面提出了when表达式
,这个是综合了它们的优点,并且增强了不少。
when
关键字用于条件分支,看起来很像是 switch 语句,不过它和switch语句最大的不同在于,when
语法支持的是一个表达式
,而表达式
就意味着,它是可以有结果的,可以作为赋值语句的右值。
以下看一个简单的例子,这个needWork
方法可以根据输入的星期的字符串,来判断是否需要上班:
怎么样?是不是使用很简单?是不是增强版的switch和 if else。
4. 协程
协程的概念是在go语言的兴起之后才逐渐火起来的。协程是轻量级的线程,因为Java 的线程是资源消耗很大的,它直接对应于底层操作系统的线程,而这就限制了在JVM中无法非常大量地创建线程。而协程相对就轻量很多,可以随便创建成千上万个都无压力。
Kotlin 就官方支持了协程的特性,虽说在Android开发中没有需要创建成千上万个协程的场景,但是有了协程后,一些异步的任务就变得非常得方便了。
|
|
5. lazy 初始化(属性委托)
熟悉Java设计模式的同学一定会知道“委托模式(也称为代理模式)
”,而Kotlin则直接将委托的机制实现在了语法层面,那就是使用 by
关键字。
不过这里我们不讲类的委托,而是讲一下 Kotlin 里面的属性委托,属性委托可以把一个成员的熟悉,委托给另一个属性来,最常用的就是用来实现懒加载。
|
|
6. lambda 表达式
lambda 表达式基本是现代语言人手一个的特性了,你一个编程语言要每个lambda 表示式都不好意思说自己是现代语言。不过这个在Java8之后Java也是支持了的。这个就不讲了
7. 扩展功能(装饰器模式)
Kotlin支持通过扩展功能
的特性来对一些当前已经存在的类方法进行扩展,而不用去改变现有的类。这个其实就是把设计模式中的“装饰器模式
”直接内置到语法层面了。
比如基于现有的String
类,给它扩展一个 hellowWorld出来:
不过需要注意的是,Kotlin中的扩展功能,并不是真的修改了原有的类的结构,它只是允许给声明了扩展功能的类,能够使用”.” 点访问而已,其实本质上是一个语法糖。
当然,Kotlin 的扩展功能也是不支持多态的,在某一个类上进行扩展,那就只是支持这个类,而不是去动态分发给它的实际的子类类型。
不过用起来是挺爽。
8. 扩展的集合
有了上一章节提到的“扩展功能的支持”,其实就能搞一些好玩的事情了,可以对一些内置类的功能进行一些扩展,比如:Kotlin对Java的集合类就进行了扩展。
Kotlin中的集合类,底层也是基于Java的集合类框架的,同时在上层使用扩展功能
来给原来的Java集合类框架添加了一些很实用的其他功能。比如说分组、聚合操作(求最大值、最小值、平均值等等)等。
这里有非常多的实用方法,具体可以参考:
https://www.kotlincn.net/docs/reference/collections-overview.html
9. 对象声明
单例模式在实践中非常常见,在Kotlin里面也有了专门针对单例模式的支持,那就是对象声明:
声明一个单例模式的对象变得如此简单(终于不用再搞单例模式的茴香豆写法了~)
10. 类型推断
类型推断也是很多语言都已经有了的,而且在Java的新版本中也是已经支持了的。
对于实际的开发来说,类型推断真的是一个非常非常好用的功能,能够给开发者节省很多的时间。
类型推断其实简单来说就一句话:当编译器能明确知道一个变量的类型的话,那么开发者就可以不用再写出来了。
其他
当然还有其他的很多不错的特性,比如说支持函数式编程,再比如可以使用tailrec
关键字来在代码层面指定进行尾递归优化等等,这里就不一一展开了,这里只是介绍我本人在实践中觉得好用而且常用的一些特性。包括但不限于这些:
- 字符串插值(或者成为字符串模版)
- 条件表达式:即条件判断语句if else 可以具有返回值
2. Kotlin 的缺点
当前,有优点,就肯定有缺点,目前还没有发现什么完美的事物是无缺的。那么接下来的章节,就来说一说Kotlin的缺点
1. 与Java结合使用的空安全
上面的章节提到了Kotlin中很好的特性“空安全”,这个特性用起来稍有不慎就会有坑,比如说在和Java库结合使用的时候,Kotlin和Java的互相调用,你会发现稍不留神就会出现一个 KotlinNullPointerException
。
这种问题就是在声明了非空的Kotin方法中,接收到了来自Java库传进来的一个null。毕竟在Java中没有这样类似的空类型检测,所以无法保证传递给Kotlin 的是非空的。
所以在Kotlin和Java相互调用的时候一定要万分小心。
2. 语法层面抛弃了static类型
Kotlin里面抛弃了Java里面的 static
关键字。反而是提出了类似的 companion object 来完成静态成员的功能。
这个怎么说呢,可以理解Kotlin是为了实现 “一切皆对象
” 的设计目标,如果保留了静态成员就达不到这个目标了。
但是这个粗暴地去掉了 static 关键字,也还是有很多不方便的地方的,这样就无法定义一些类级别的成员了,而伴生对象本质上还是一些成员对象,也无法做到和Class相关。
3. 抛弃了 Checked Exception
最后说这个,Kotlin 里面抛弃了对 Checked Exception。
先说下什么是 Checked Exception,在Java中,当一个方法的声明中有 throws
关键字来说明这个方法可能会抛出一些异常的时候,那么调用者则需要处理这些异常。
|
|
而在Kotlin中则取消了这个特性,即便调用了声明 Checked Exception 的方法而不加try catch,在Kotlin中仍然是可以编译通过的。
我认为这个做法确实是一个糟糕的设计。官方的说法是在大型项目中过多地使用 Checked Exception 会导致生产力降低生产力(https://www.kotlincn.net/docs/reference/exceptions.html)。这个观点我是无法认同的。Checked Exception 虽然在代码里面增加了很多 try catch 的代码,会让代码看起来比较丑陋,但是这个这样做却可以保证整体代码的下限不会太低,而去掉了这个Checked Exception 则使得这个下限低了很多。因为我们无法确定我们调用的方法底层有哪些地方声明了Checked Exception,这就使得我们的代码暴漏在潜在的风险里面,在某些不确定的时候将会出现Exception。
而这些Exception原本是可以通过 try catch 搞定的。