一、概述
The Kotlin 2.1.20 release is here! Here are the main highlights:
Kotlin 2.1.20发布了,主要亮点如下:
- K2 compiler updates: updates to the new kapt and Lombok plugins
- Kotlin Multiplatform: new DSL to replace Gradle’s Application plugin
- Kotlin/Native: support for Xcode 16.3 and a new inlining optimization
- Kotlin/Wasm: default custom formatters, support for DWARF, and migration to Provider API
- Gradle support: compatibility with Gradle’s Isolated Projects and custom publication variants
- Standard library: common atomic types, improved UUID support, and new time-tracking functionality
- Compose compiler: relaxed restrictions on @Composable functions and other updates
- Documentation: notable improvements to the Kotlin documentation.
二、常见原子类型
在Kotlin 2.1.20中,我们在标准库的Kotlin .concurrent.atomics包中引入了公共原子类型,为线程安全操作启用了共享的、独立于平台的代码。
通过消除跨源集复制原子相关逻辑的需要,这简化了Kotlin Multiplatform项目的开发。
kotlin.concurrent.atomics包及其属性是实验性的。要选择加入,使用@OptIn(ExperimentalAtomicApi::class)注释或编译器选项-opt-in=kotlin.ExperimentalAtomicApi。
下面是一个示例,展示了如何使用AtomicInt在多个线程中安全地计数已处理的项:
示例执行效果图
@OptIn(ExperimentalAtomicApi::class)
suspend fun testExperimentalAtomicApi() {
var processedItems = AtomicInt(0)
val totalItems = 100
val items = List(totalItems) { "item$it" }
// Splits the items into chunks for processing by multiple coroutines
val chunkSize = 20
val itemChunks = items.chunked(chunkSize)// chunked函数 将List分割为指定大小的子数组(List),
// itemChunks 5个数组,每个数组里有20个元素
coroutineScope {
for (chunk in itemChunks) {
launch {
for (item in chunk) {
println("Processing $item in thread ${Thread.currentThread()}")
processedItems.incrementAndFetch()
}
}
}
}
println("processedItems = $processedItems")
}
suspend fun main() {
testExperimentalAtomicApi()
}
为了在Kotlin的原子类型和Java的Java .util.concurrent.atomic原子类型之间实现无缝的互操作性,API提供了. asjavaatomic()和. askotlinatomic()扩展函数。
在JVM上,Kotlin原子和Java原子在运行时是相同的类型,因此您可以在没有任何开销的情况下将Java原子转换为Kotlin原子,反之亦然。
下面的例子展示了Kotlin和Java原子类型是如何协同工作的:
执行示例效果图
@OptIn(ExperimentalAtomicApi::class)
fun testExperimentalAtomicApi11(){
// Converts Kotlin AtomicInt to Java's AtomicInteger
val kotlinAtomic = AtomicInt(24)
val javaAtomic: AtomicInteger = kotlinAtomic.asJavaAtomic()
println("转换 Java atomic 原始 value: ${javaAtomic.get()}")
// 转换 Java atomic 原始 value: 24
javaAtomic.incrementAndGet()
println("转换 Java atomic 后 自增1次 value: ${javaAtomic.get()}")
// 转换 Java atomic 后 自增1次 value: 25
// Converts Java's AtomicInteger back to Kotlin's AtomicInt
val kotlinAgain: AtomicInt = javaAtomic.asKotlinAtomic()
println("转换 Kotlin atomic 原始 value: ${kotlinAgain.load()}")
//转换 Kotlin atomic 原始 value: 25
kotlinAgain.incrementAndFetch()
println("转换 Kotlin atomic 后 自增1次 value: ${kotlinAgain.load()}")
// 转换 Kotlin atomic 后 自增1次 value: 26
}
suspend fun main() {
testExperimentalAtomicApi11()
}
三、UUID解析、格式和可比性的变化
JetBrains团队继续在2.0.20中改进对标准库中引入的uuid的支持。
以前,parse()函数只接受十六进制和破折号格式的uuid。在Kotlin 2.1.20中,可以对十六进制-破折号和普通十六进制(不带破折号)格式使用parse()。
在这个版本中,我们还引入了一些特定于十六进制和破折号格式操作的函数:
- parseHexDash()从十六进制和破折号格式解析uid。
- toHexDashString()将Uuid转换为十六进制和破折号格式的String(镜像toString()的功能)。
这些函数的工作方式类似于前面介绍的十六进制格式的parseHex()和toHexString()。解析和格式化功能的显式命名应该会提高代码的清晰度和您使用uid的总体体验。
Kotlin中的uid现在是可比的。从Kotlin 2.1.20开始,您可以直接比较和排序Uuid类型的值。这允许使用<和>操作符和标准库扩展,这些扩展专门用于Comparable类型或它们的集合(例如sorted()),并且它还允许将uuid传递给需要Comparable接口的任何函数或api。
请记住,标准库中的UUID支持仍然是实验性的。要选择加入,使用@OptIn(ExperimentalUuidApi::class)注释或编译器选项-opt-in=kotlin.uuid.ExperimentalUuidApi::
执行示例效果图
@OptIn(ExperimentalUuidApi::class)
fun testExperimentalUuidApi(){
// parse() accepts a UUID in a plain hexadecimal format
val uuid = Uuid.parse("550e8400e29b41d4a716446655440000")
// Converts it to the hex-and-dash format
val hexDashFormat = uuid.toHexDashString()
// Outputs the UUID in the hex-and-dash format
println(hexDashFormat)
// 550e8400-e29b-41d4-a716-446655440000
// Outputs UUIDs in ascending order
println(
listOf(
uuid,
Uuid.parse("780e8400e29b41d4a716446655440005"),
Uuid.parse("5ab88400e29b41d4a716446655440076")
).sorted()
)
// [550e8400-e29b-41d4-a716-446655440000, 5ab88400-e29b-41d4-a716-446655440076, 780e8400-e29b-41d4-a716-446655440005]
}
fun main() {
testExperimentalUuidApi()
}
四、新的时间跟踪功能
从Kotlin 2.1.20开始,标准库提供了表示某个时刻的能力。此功能以前仅在Kotlin官方库kotlinx-datetime中可用。
kotlinx.datetime.Clock接口以kotlin.time.Clock的形式引入标准库,kotlinx.datetime.Instant类以kotlin.time.Instant的形式引入标准库。这些概念很自然地与标准库中的时间包保持一致,因为与kotlinx-datetime中保留的更复杂的日历和时区功能相比,它们只关注时间中的时刻。
当您需要精确的时间跟踪而不考虑时区或日期时,Instant和Clock是有用的。例如,您可以使用它们来记录带有时间戳的事件,度量两个时间点之间的持续时间,并获得系统进程的当前时刻。
为了提供与其他语言的互操作性,可以使用额外的转换器功能:
- tokotlininstant()将时间值转换为kotlin.time.Instant实例。
- tojavainstant()将kotlin.time.Instant值转换为java.time.Instant值。
- Instant.toJSDate()将kotlin.time.Instant值转换为JSDate类的一个实例。这种转换并不精确;JS使用毫秒级的精度来表示日期,而Kotlin允许纳秒级的分辨率。
标准库的新时间特性仍处于试验阶段。要选择加入,请使用@OptIn(ExperimentalTime::class)注释:
执行示例效果图
@OptIn(ExperimentalTime::class)
fun testTimeClock() {
// Get the current moment in time
val currentInstant = Clock.System.now()
println("Current time: $currentInstant")
// Find the difference between two moments in time
val pastInstant = Instant.parse("2023-01-01T00:00:00Z")
val duration = currentInstant - pastInstant
println("Time elapsed since 2023-01-01: $duration")
}
fun main() {
testTimeClock()
}