Kotlin 1.3 release 到现在已经一个多月了,除了协程正式 release 之外,还是有些别的惊喜的。比如 contract, 无符号整型, inline class 以及各种各样的语法糖,回顾一下。
协程 正式 release 了
这个一言难尽,直接左转吧:http://kotlinlang.org/docs/reference/coroutines-overview.html
Contracts | 契约*
Kotlin 编译器进行拓展静态分析来提供警告并且避免模板代码。 最有意义的一个 feature 是 智能转型——针对既有的类型检查来自动进行类型转换。
如果写过 Java 的话,对下面这段代码应该不是很陌生:这个强制类型转换看起来就很“多余”。
1 | Object obj = foo(); // public static Object foo() { return "Boom!"; } |
再看这段代码(对于 Kotlin 的类型系统,String?
和 String
是两个不同的类型),这里展示了智能转型的语法糖:
1 | fun foo(s: String?) { |
但是,这个检查比较粗糙(或者说由于性能等方面的考量,难以做得细致),一旦我们把这些检查放到单独的函数,智能转型就会失效:
1 | fun foo(str: String?) { |
所以,引入了 contract,这样重写 String?.isNotNull()
就好了:
1 |
|
标准库中的 contract
Kotlin stdlib
已经在使用 contract 了,比如这种(Strings.kt:218):
1 | /** |
自定义 contract
现在 contract 还是 Experimental 的,编译器并不会检查这些契约,甚至 contract 的格式/语法还极大可能发生变化。
就编程风格来说,一般有 defensive(检查参数,甚至返回默认值) 和 aggressive(反手就是一个
IllegalArgumentException
) 两个流派,这个没有是非对错之分,更多的只是在某种情形下执行某种实践(甚至很多团队对此没有统一的 约束)。所以感觉 contract 这个东西还是太理想化了,毒奶一口,目测会 deprecated。
自定义 contract 就是在 contract
DSL 里来这么一句:returns xx implies xx
(如果返回值是啥啥啥,意味着啥啥啥)。 下面是一个例子:
1 |
|
捕获 when
的参数作为变量
针对使用 when
的某一特殊场景,可以少些几行代码。可以这么写:
1 | when (val data = fetchData()) { |
而不是这么写:
1 | fetchData().also { data -> |
在接口的伴生对象中使用 @JvmStatic
和 @JvmField
注解
可以这么写了:
1 | interface Foo { |
等价的 Java 形式:
1 | interface Foo { |
注解类的嵌套声明
1 | annotation class Foo { |
无参的 main
方法
嗯,一下子少了 19 个字符
1 | fun main() { /* Yeah! */ } |
参数巨多的 Function
Function0<R>
, Function1<P0, R>
, Function2<P0, P1, R>
, 之前是到 Function22
. Kotlin 1.3 中引入了 FunctionN, 以可变参数(或者说数组)的形式进行扩充。
Before:
1 | fun naiveKotlin(block: (Any, Any, Any) -> Any) { } |
1 | // #1 |
After:
1 | fun trueEnterpriseComesToKotlin(block: (Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, |
1 | MainKt.trueEnterpriseComesToKotlin(new FunctionN<Object>() {}); |
内联类
1 | inline class Name(val s: String) |
内联类是对普通的类施加了很多限制以便于进行各种各样的优化。
内联类只能有一个字段(属性)。
@JvmDefault
注解*
1 | interface Foo { |
会编译为 Java 的接口默认方法(since JDK8),因此可能会对代码的可移植性造成不好的影响
标准库的变化
数组间元素复制
更 Kotlin 了
1 | val sourceArr = arrayOf("k", "o", "t", "l", "i", "n") |
associateWith
List
到 Map
的变换,现在可以这样写了:
1 | List(5) { idx -> 'a' + idx } |
之前要这样写:
1 | List(5) { idx -> 'a' + idx } |
都会产生相同的输出:
1 | a=Aaaaa |
其他细微更改
多平台的 Random
isNullOrEmpty/orEmpty
拓展函数
ifEmpty & ifBlank
反射中的 sealed class
此外,还有这些:
- 无符号整数
- Progressive Mode
- Coroutines Release
- Kotlin/Native
- Multiplatform Projects
- 代码风格 IDE 支持
- kotlinx.serialization
- Kotlin Script
- Kotlin Scratch