- 1:语言的功能和改进
- 1.1:Kotlin 接口的SAM转换
- 1.2:库作者的显式API模式
- 1.3:混合命名和位置参数
- 1.4:尾部逗号
- 1.5:可调用的改进
- 1.6:when列入循环表达式中使用break与continue
- 2:IDE的新工具
- 2.1:更灵活的项目引导
- 2.2:协程调试器
- 3:标准库改进
- 3.1:常见异常处理API
- 3.2:数据和集合的新功能
- 3.3:字符串操作函数
- 3.4:位操作
- 3.5:从KType转换为Java类型
- 3.6:用于Kotlin反射的Proguard配置
- 3.7:改善现有的API
- 3.8:stdlib工件的模块信息描述符
- 3.9:弃用
- 3.10:不推荐使用的实验协程
- 4:稳定的JSON序列化
在已经过去的八月中旬,JetBrains的Kotlin项目组发布了Kotlin 1.4版本。 在该版本中,Kotlin团队投入了大量精力和努力来提高 Kotlin 及其工具的性能和质量。 并且支持多种新的语言功能,包括期待已久的 Kotlin 接口的 SAM 转换。
语言的功能和改进
Kotlin 接口的SAM转换
在Kotlin 1.4.0之前,仅当使用Kotlin的Java方法和Java接口时,才能应用SAM(单一抽象方法)转换。从现在开始,也可以将SAM转换用于Kotlin接口。在使用fun
修饰符将Kotlin接口明确标记为可正常使用。
如果仅将一个抽象方法的接口作为参数,则将lambda作为参数传递时,将应用SAM转换。在这种情况下,编译器会自动将lambda转换为实现抽象成员函数的类的实例。
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
val isEven = IntPredicate { it % 2 == 0 }
fun main() {
println("Is 7 even? - ${isEven.accept(7)}")
}
库作者的显式API模式
Kotlin编译器为库作者提供了显式的API模式。在这种模式下,编译器将执行其他检查,以帮助使库的API更清晰,更一致。它为暴露给库的公共API的声明增加了以下要求:
- 如果默认可见性将其公开给公共API,则声明必须使用可见性修饰符。这有助于确保任何声明都不会无意间暴露给公共API。
- 对于公开API公开的属性和函数,需要明确的类型规范。这样可以保证API使用者知道他们使用的API成员的类型。
根据配置,这些显式API可能会产生错误(严格模式)或警告(警告模式)。为了便于阅读和常识,某些类型的声明从此类检查中排除:
- 主要构造函数
- 数据类的属性
- 属性的setters和getters
- override方法
要以显式API模式编译模块,在Gradle构建脚本中添加以下几行:
kotlin {
// for strict mode
explicitApi()
// or
explicitApi = 'strict'
// for warning mode
explicitApiWarning()
// or
explicitApi = 'warning'
}
混合命名和位置参数
在Kotlin 1.3中,在使用命名参数调用函数时,必须将所有不带名称的参数(位置参数)放在第一个命名参数之前。例如,可以执行f(1, y = 2)
,但不能执行f(x = 1, 2)
。
当所有参数都位于正确的位置时确实很烦人,但是想在中间为一个参数指定一个名称。这对于绝对清楚地说明布尔值或null
值属于哪个属性特别有用。
在Kotlin 1.4中,没有这种限制-现在可以在一组位置参数的中间为参数指定名称。此外,还可以按自己喜欢的任何方式混合使用位置和命名参数,只要它们保持正确的顺序即可。
fun reformat(
str: String,
uppercaseFirstLetter: Boolean = true,
wordSeparator: Character = ' '
) {
// ...
}
//中间带有命名参数的调用
reformat('This is a String!', uppercaseFirstLetter = false , '-')
尾部逗号
使用Kotlin 1.4,可以在枚举中添加尾部逗号,例如参数和参数列表,when
条目以及解构声明的组件。使用结尾逗号,可以添加新项并更改其顺序,而无需添加或删除逗号。
如果对参数或值使用多行语法,这将特别有用。添加结尾逗号后,可以轻松地将行与参数或值交换。
fun reformat(
str: String,
uppercaseFirstLetter: Boolean = true,
wordSeparator: Character = ' ', //尾部逗号
) {
// ...
}
val colors = listOf(
"red",
"green",
"blue", //尾部逗号
)
可调用的改进
Kotlin 1.4支持更多使用可调用引用的情况:
- 对具有默认参数值的函数的引用
- 在函数引用
Unit
-returning功能 - 根据函数中的参数数量进行适应的引用
- 挂起可调用引用的转换
对具有默认参数值的函数的引用
现在,可以使用具有默认参数值的函数的可调用引用。例如,如果对函数的可调用引用foo
不带任何参数,0
则使用默认值。
fun foo(i: Int = 0): String = "$i!"
fun apply(func: () -> String): String = func()
fun main() {
println(apply(::foo))
}
在1.4版本前,必须为函数编写其他重载apply
以使用默认参数值。
// 新的重载方法
fun applyInt(func: (Int) -> String): String = func(0)
在函数引用Unit
-returning功能
在Kotlin 1.4中,可以使用可调用引用来在Unit
-returning函数中返回任何类型的函数。在Kotlin 1.4之前,只能在这种情况下使用lambda参数。现在,可以同时使用lambda参数和可调用引用。
fun foo(f: () -> Unit) { }
fun returnsInt(): Int = 42
fun main() {
foo { returnsInt() } // 1.4之前
foo(::returnsInt) // 1.4版本也可以
}
根据函数中的参数数量进行适应的引用
现在,当传递可变数量的参数(vararg
)时,可以使可调用引用适应函数。可以在传递的参数列表的末尾传递任意数量的相同类型的参数。
fun foo(x: Int, vararg y: String) {}
fun use0(f: (Int) -> Unit) {}
fun use1(f: (Int, String) -> Unit) {}
fun use2(f: (Int, String, String) -> Unit) {}
fun test() {
use0(::foo)
use1(::foo)
use2(::foo)
}
挂起可调用引用的转换
除了在lambda上挂起转换外,Kotlin现在还支持从1.4.0版本开始对可调用引用进行挂起转换。
fun call() {}
fun takeSuspend(f: suspend () -> Unit) {}
fun test() {
takeSuspend { call() } // 1.4之前
takeSuspend(::call) // 1.4
}
when列入循环表达式中使用break与continue
在Kotlin 1.3中,不能使用循环中包含的不合格表达式break
和continue
内部when
表达式。其原因是,这些关键字都留给了可能落空行为的when
表现形式。
这就是为什么如果要在循环中使用表达式break
和continue
内部when
表达式,则必须标记它们,这变得相当麻烦。
fun test(xs: List<Int>) {
LOOP@for (x in xs) {
when (x) {
2 -> continue@LOOP
17 -> break@LOOP
else -> println(x)
}
}
}
在Kotlin 1.4中,可以在循环中包含的表达式内使用break
和continue
不使用标签when
。它们可以通过终止最近的封闭循环或进行下一步来达到预期的效果。
fun test(xs: List<Int>) {
for (x in xs) {
when (x) {
2 -> continue
17 -> break
else -> println(x)
}
}
}
IDE的新工具
使用Kotlin 1.4,可以使用IntelliJ IDEA中的新工具来简化Kotlin开发:
- 更灵活的项目引导
- 协程调试器
更灵活的项目引导
使用灵活的新Kotlin项目向导,可以轻松创建和配置不同类型的Kotlin项目,包括多平台项目:
新的Kotlin项目向导既简单又灵活:
1.选择项目模板,具体取决于您要执行的操作。将来会添加更多模板。
2.选择构建系统 -Gradle(Kotlin或Groovy DSL),Maven或IntelliJ IDEA。Kotlin项目向导将仅显示所选项目模板上支持的构建系统。
3.直接在主屏幕上预览项目结构。
然后,可以完成创建项目,或者(可选)在下一个屏幕上配置项目:
4.添加/删除此项目模板支持的模块和目标。
5.配置模块和目标设置,例如目标JVM版本,目标模板和测试框架。
协程调试器
许多人已经使用协程进行异步编程。但是,当涉及调试时,在Kotlin 1.4之前使用协程可能会非常痛苦。由于协程在线程之间跳转,因此很难了解特定协程在做什么并检查其上下文。在某些情况下,跟踪断点上的步骤根本行不通。结果,必须依靠日志记录或精力来调试使用协程的代码。
在Kotlin 1.4中,借助Kotlin插件附带的新功能,调试协程现在变得更加方便。调试适用于1.3.8或更高版本kotlinx-coroutines-core
。
在调试工具窗口现在包含一个新的协同程序选项卡。在此标签中,可以找到有关当前正在运行和已挂起的协程的信息。协程由运行它们的调度程序分组。
现在可以:
- 轻松检查每个协程的状态。
- 查看正在运行的和暂停的协程的局部变量和捕获变量的值。
- 查看完整的协程创建堆栈以及协程内部的调用堆栈。堆栈包括具有可变值的所有帧,甚至包括那些在标准调试期间会丢失的帧。
如果需要一个包含每个协程和它的堆栈的状态的完整报告,里面右键单击协同程序选项卡,然后单击 Get Coroutines Dump:
标准库改进
以下列出了1.4.0中对Kotlin标准库的最重要更改:
- 常见异常处理API
- 数组和集合的新功能
- 字符串操作函数
- 位操作
- 委派的改善
- 从KType转换为Java类型
- 用于Kotlin反射的Proguard配置
- 改善现有的API
- stdlib工件的模块信息描述符
- 弃用
- 不推荐使用的实验协程
常见异常处理API
以下API元素已移至公共库:
Throwable.stackTraceToString()
扩展函数,它返回此throwable的详细描述及其堆栈跟踪,以及Throwable.printStackTrace()
,该函数将该描述打印到标准错误输出。Throwable.addSuppressed()
函数(可用于指定为传递异常而抑制的异常)和Throwable.suppressedExceptions
属性(可返回所有抑制的异常的列表)的属性。@Throws
注解,其中列出了将函数编译为平台方法(在JVM或本机平台上)时将检查的异常类型。
数据和集合的新功能
集合
在1.4.0版中,标准库包含许多有用的用于处理集合的函数:
setOfNotNull()
,生成一个由提供的参数中所有非空项目组成的集合。
val set = setOfNotNull(null, 1, 2, 0, null)
println(set) //打印 1,2,0
shuffled()
对于序列。
val numbers = (0 until 50).asSequence()
val result = numbers.map { it * 2 }.shuffled().take(5)
println(result.toList()) //低于100的五个随机偶数
*OrNull()
同行randomOrNull()
,reduceOrNull()
和reduceIndexedOrNull()
。他们返回null
空集合。
val empty = emptyList<Int>()
empty.reduceOrNull { a, b -> a + b }
//empty.reduce { a, b -> a + b } // 异常: 空集合不能减少.
runningFold()
,它的同义词scan()
,并runningReduce()
类似于fold()
和顺序地将给定操作应用于集合元素reduce()
。不同之处在于这些新函数返回中间结果的整个序列。
val numbers = mutableListOf(0, 1, 2, 3, 4, 5)
val runningReduceSum = numbers.runningReduce { sum, item -> sum + item }
val runningFoldSum = numbers.runningFold(10) { sum, item -> sum + item }
sumOf()
接受选择器函数,并为集合的所有元素返回其值的总和。sumOf()
能够生产的各类款项Int
,Long
,Double
,UInt
,和ULong
。在JVM上,BigInteger
并且BigDecimal
也可提供。
val order = listOf<OrderItem>(
OrderItem("Cake", price = 10.0, count = 1),
OrderItem("Coffee", price = 2.5, count = 3),
OrderItem("Tea", price = 1.5, count = 2))
val total = order.sumOf { it.price * it.count} // Double
val count = order.sumOf { it.count } // Int
- 该
min()
和max()
功能已更名为minOrNull()
和maxOrNull()
符合整个Kotlin集合API使用的命名约定。*OrNull
函数名称中的后缀表示null
如果接收者集合为空,则返回。这同样适用于minBy()
,maxBy()
,minWith()
,maxWith()
在1.4,他们有*OrNull()
同义词。
数组
为了在使用不同的容器类型时提供一致的体验,还为数组添加了新功能:
shuffle()
将数组元素以随机顺序放置。onEach()
对每个数组元素执行给定的操作并返回数组本身。associateWith()
并associateWithTo()
使用数组元素作为键构建映射。reverse()
对于数组子范围,将反转子范围中元素的顺序。sortDescending()
对于数组子范围,按降序对子范围中的元素进行排序。sort()
和sortWith()
数组子范围,现在在公共库提供。
字符串操作函数
1.4.0中的标准库在字符串处理的API中进行了许多改进:
StringBuilder
有一些有用的新扩展函数:set()
,setRange()
,deleteAt()
,deleteRange()
,appendRange()
。
val sb = StringBuilder("Bye Kotlin 1.3.72")
sb.deleteRange(0, 3)
sb.insertRange(0, "Hello", 0 ,5)
sb.set(15, '4')
sb.setRange(17, 19, "0")
print(sb.toString()) //打印 Hello Kotlin 1.4.0
StringBuilder
公共库中提供了的一些现有功能。其中包括append()
,insert()
,substring()
,setLength()
,等等。- 新功能
Appendable.appendLine()
和StringBuilder.appendLine()
已添加到公共库。它们替换了appendln()
这些类的仅JVM 功能。
println(buildString {
appendLine("Hello,")
appendLine("world")
})
位操作
位操作的新功能:
- countOneBits()
- countLeadingZeroBits()
- countTrailingZeroBits()
- takeHighestOneBit()
- takeLowestOneBit()
委托的改善
在1.4.0中,添加了新功能来改善在Kotlin中使用委托属性的体验:
- 现在可以将一个属性委派给另一个属性。
- 新的接口
PropertyDelegateProvider
有助于在单个声明中创建委托提供程序。 ReadWriteProperty
现在扩展,ReadOnlyProperty
因此可以将它们都用于只读属性。
从KType转换为Java类型
KType.javaType
stdlib中的新扩展属性(当前为实验性)可帮助java.lang.reflect.Type
从Kotlin类型获取a 而不使用整个kotlin-reflect
依赖关系。
import kotlin.reflect.javaType
import kotlin.reflect.typeOf
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> accessReifiedTypeArg() {
val kType = typeOf<T>()
println("Kotlin type: $kType")
println("Java type: ${kType.javaType}")
}
@OptIn(ExperimentalStdlibApi::class)
fun main() {
accessReifiedTypeArg<String>()
// Kotlin type: kotlin.String
// Java type: class java.lang.String
accessReifiedTypeArg<List<String>>()
// Kotlin type: kotlin.collections.List<kotlin.String>
// Java type: java.util.List<java.lang.String>
}
用于Kotlin反射的Proguard配置
从1.4.0版开始,在中嵌入了Kotlin Reflection的Proguard / R8配置kotlin-reflect.jar
。有了这个功能,大多数使用R8或Proguard的Android项目都应该可以与kotlin-reflect一起使用,而无需任何其他配置。不再需要复制粘贴Kotlin反射内部构件的Proguard规则。但是请注意,仍然需要显式列出要考虑的所有API。
改善现有的API
NaN
,,NEGATIVE_INFINITY
和POSITIVE_INFINITY
inDouble
和Float
现在定义为const
,因此可以将它们用作注释参数。- 新的常数
SIZE_BITS
并且SIZE_BYTES
在Double
与Float
包含的比特数和字节用于表示以二进制形式的类型的一个实例。 maxOf()
和minOf()
顶级函数可以接受可变数量的参数(vararg
)。
stdlib工件的模块信息描述符
Kotlin 1.4.0将module-info.java
模块信息添加到默认的标准库工件。这使可以将它们与jlink工具一起使用 ,该工具会生成自定义Java运行时映像,该映像仅包含应用程序所需的平台模块。已经可以将jlink与Kotlin标准库工件一起使用,但是必须使用单独的工件(即带有“模块化”分类器的工件)来进行操作。
在Android中,确保使用3.2或更高版本的Android Gradle插件,该插件可以正确地使用module-info处理jar文件。
弃用
Double和Float的toShort()和toByte()
不建议使用的功能toShort()
,并toByte()
在Double
和Float
,因为它们可能会导致由于窄值范围意想不到的效果和更小的尺寸可变。要将浮点数转换为Byte
或Short
,请使用两步转换:首先,将它们转换为Int
,然后再次将它们转换为目标类型。
浮点数组上的contains(),indexOf()和lastIndexOf()
已经废弃了contains()
,indexOf()
和lastIndexOf()
扩展功能,FloatArray
并且DoubleArray
因为它们使用IEEE 754标准的平等。
min()和max()集合函数
不赞成min()
and max()
集合函数,而赞成minOrNull()
and maxOrNull()
,它们更恰当地反映了它们的行为-返回null
空集合。
不推荐使用的实验协程
kotlin.coroutines.experimental
在1.3.0中,不推荐使用该API,而推荐使用kotlin.coroutines。在1.4.0中,kotlin.coroutines.experimental
通过从标准库中删除折旧周期来完成折旧周期。对于仍然在JVM上使用它的人,提供了kotlin-coroutines-experimental-compat.jar
与所有实验协程API 的兼容性工件。已经将其发布到Maven,并将其与标准库一起包含在Kotlin发行版中。
稳定的JSON序列化
随着Kotlin 1.4.0的发布,发布了kotlinx.serialization的第一个稳定版本:1.0.0-RC。JSON序列化API处于kotlinx-serialization-core
(以前称为kotlinx-serialization-runtime
)稳定状态。其他序列化格式的库以及核心库的某些高级部分仍处于试验阶段。