Kotlin 1.6.0 的新特性


Kotlin 1.6.0 引入了新的语言特性、对现有特性的优化与改进以及对 Kotlin 标准库的大量改进。



Kotlin 1.6.0 将上一版本 1.5.30 中预览的几个语言特性提升为稳定版了:


稳定版对于枚举、密封类与布尔值主语穷尽 when 语句

An exhaustive when statement contains branches for all possible types or values of its subject, or for some types plus an else branch. It covers all possible cases, making your code safer.

We will soon prohibit non-exhaustive when statements to make the behavior consistent with when expressions. To ensure smooth migration, Kotlin 1.6.0 reports warnings about non-exhaustive when statements with an enum, sealed, or Boolean subject. These warnings will become errors in future releases.

sealed class Contact {
    data class PhoneCall(val number: String) : Contact()
    data class TextMessage(val number: String) : Contact()

fun Contact.messageCost(): Int =
    when(this) { // Error: 'when' expression must be exhaustive
        is Contact.PhoneCall -> 42

fun sendMessage(contact: Contact, message: String) {
    // Starting with 1.6.0

    // Warning: Non exhaustive 'when' statements on Boolean will be
    // prohibited in 1.7, add 'false' branch or 'else' branch instead 
    when(message.isEmpty()) {
        true -> return
    // Warning: Non exhaustive 'when' statements on sealed class/interface will be
    // prohibited in 1.7, add 'is TextMessage' branch or 'else' branch instead
    when(contact) {
        is Contact.PhoneCall -> TODO()

See this YouTrack ticket for a more detailed explanation of the change and its effects.


Implementation of suspending functional types has become Stable in Kotlin 1.6.0. A preview was available in 1.5.30.

The feature can be useful when designing APIs that use Kotlin coroutines and accept suspending functional types. You can now streamline your code by enclosing the desired behavior in a separate class that implements a suspending functional type.

class MyClickAction : suspend () -> Unit {
    override suspend fun invoke() { TODO() }

fun launchOnClick(action: suspend () -> Unit) {}

You can use an instance of this class where only lambdas and suspending function references were allowed previously: launchOnClick(MyClickAction()).

There are currently two limitations coming from implementation details:

  • You can't mix ordinary functional types and suspending ones in the list of supertypes.
  • You can't use multiple suspending functional supertypes.


Kotlin 1.6.0 introduces Stable conversions from regular to suspending functional types. Starting from 1.4.0, the feature supported functional literals and callable references. With 1.6.0, it works with any form of expression. As a call argument, you can now pass any expression of a suitable regular functional type where suspending is expected. The compiler will perform an implicit conversion automatically.

fun getSuspending(suspending: suspend () -> Unit) {}

fun suspending() {}

fun test(regular: () -> Unit) {
    getSuspending { }           // OK
    getSuspending(::suspending) // OK
    getSuspending(regular)      // OK


Kotlin 1.5.30 introduced experimental support for instantiation of annotation classes on the JVM platform. With 1.6.0, the feature is available by default both for Kotlin/JVM and Kotlin/JS.

Learn more about instantiation of annotation classes in this KEEP.


Kotlin 1.5.30 introduced an improvement to type inference for recursive generic types, which allowed their type arguments to be inferred based only on the upper bounds of the corresponding type parameters. The improvement was available with the compiler option. In version 1.6.0 and later, it is enabled by default.

// Before 1.5.30
val containerA = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:13-alpine")).apply {

// With compiler option in 1.5.30 or by default starting with 1.6.0
val containerB = PostgreSQLContainer(DockerImageName.parse("postgres:13-alpine"))


Builder inference is a type inference flavor which is useful when calling generic builder functions. It can infer the type arguments of a call with the help of type information from calls inside its lambda argument.

We're making multiple changes that are bringing us closer to fully stable builder inference. Starting with 1.6.0:

  • You can make calls returning an instance of a not yet inferred type inside a builder lambda without specifying the -Xunrestricted-builder-inference compiler option introduced in 1.5.30.
  • With -Xenable-builder-inference, you can write your own builders without applying the @BuilderInference annotation.

    Note that clients of these builders will need to specify the same -Xenable-builder-inference compiler option.

  • With the -Xenable-builder-inference, builder inference automatically activates if a regular type inference cannot get enough information about a type.

Learn how to write custom generic builders.


对类的类型参数上注解的支持 looks like this:

annotation class BoxContent

class Box<@BoxContent T> {}

Annotations on all type parameters are emitted into JVM bytecode so annotation processors are able to use them.

For the motivating use case, read this YouTrack ticket.

Learn more about annotations.

对以前版本的 API 支持更长时间

Starting with Kotlin 1.6.0, we will support development for three previous API versions instead of two, along with the current stable one. Currently, we support versions 1.3, 1.4, 1.5, and 1.6.


For Kotlin/JVM, starting with 1.6.0, the compiler can generate classes with a bytecode version corresponding to JVM 17. The new language version also includes optimized delegated properties and repeatable annotations, which we had on the roadmap:

1.8 JVM 目标平台中运行时保留的可重复注解

Java 8 introduced repeatable annotations, which can be applied multiple times to a single code element. The feature requires two declarations to be present in the Java code: the repeatable annotation itself marked with @java.lang.annotation.Repeatable and the containing annotation to hold its values.

Kotlin also has repeatable annotations, but requires only @kotlin.annotation.Repeatable to be present on an annotation declaration to make it repeatable. Before 1.6.0, the feature supported only SOURCE retention and was incompatible with Java's repeatable annotations. Kotlin 1.6.0 removes these limitations. @kotlin.annotation.Repeatable now accepts any retention and makes the annotation repeatable both in Kotlin and Java. Java's repeatable annotations are now also supported from the Kotlin side.

While you can declare a containing annotation, it's not necessary. For example:

  • If an annotation @Tag is marked with @kotlin.annotation.Repeatable, the Kotlin compiler automatically generates a containing annotation class under the name of @Tag.Container:

      annotation class Tag(val name: String)
      // The compiler generates @Tag.Container containing annotation
  • To set a custom name for a containing annotation, apply the @kotlin.jvm.JvmRepeatable meta-annotation and pass the explicitly declared containing annotation class as an argument:

      annotation class Tag(val name: String)
      annotation class Tags(val value: Array<Tag>)

Kotlin reflection now supports both Kotlin's and Java's repeatable annotations via a new function, KAnnotatedElement.findAnnotations().

Learn more about Kotlin repeatable annotations in this KEEP.

优化了在给定 KProperty 实例上调用了 get/set 的委托属性

We optimized the generated JVM bytecode by omitting the $delegate field and generating immediate access to the referenced property.

For example, in the following code

class Box<T> {
    private var impl: T = ...

    var content: T by ::impl

Kotlin no longer generates the field content$delegate. Property accessors of the content variable invoke the impl variable directly, skipping the delegated property's getValue/setValue operators and thus avoiding the need for the property reference object of the KProperty type.

Thanks to our Google colleagues for the implementation!

Learn more about delegated properties.


Kotlin/Native is receiving multiple improvements and component updates, some of them in the preview state:


The new Kotlin/Native memory manager is Experimental. It may be dropped or changed at any time. Opt-in is required (see details below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.

With Kotlin 1.6.0, you can try the development preview of the new Kotlin/Native memory manager. It moves us closer to eliminating the differences between the JVM and Native platforms to provide a consistent developer experience in multiplatform projects.

One of the notable changes is the lazy initialization of top-level properties, like in Kotlin/JVM. A top-level property gets initialized when a top-level property or function from the same file is accessed for the first time. This mode also includes global interprocedural optimization (enabled only for release binaries), which removes redundant initialization checks.

We've recently published a blog post about the new memory manager. Read it to learn about the current state of the new memory manager and find some demo projects, or jump right to the migration instructions to try it yourself. Please check how the new memory manager works on your projects and share feedback in our issue tracker, YouTrack.

对 Xcode 13 的支持

Kotlin/Native 1.6.0 supports Xcode 13 – the latest version of Xcode. Feel free to update your Xcode and continue working on your Kotlin projects for Apple operating systems.

New libraries added in Xcode 13 aren't available for use in Kotlin 1.6.0, but we're going to add support for them in upcoming versions.

在任何主机上编译 Windows 目标

Starting from 1.6.0, you don't need a Windows host to compile the Windows targets mingwX64 and mingwX86. They can be compiled on any host that supports Kotlin/Native.

LLVM 与链接器更新

We've reworked the LLVM dependency that Kotlin/Native uses under the hood. This brings various benefits, including:

  • Updated LLVM version to 11.1.0.
  • Decreased dependency size. For example, on macOS it's now about 300 MB instead of 1200 MB in the previous version.
  • Excluded dependency on the ncurses5 library that isn't available in modern Linux distributions.

In addition to the LLVM update, Kotlin/Native now uses the LLD linker (a linker from the LLVM project) for MingGW targets. It provides various benefits over the previously used ld.bfd linker, and will allow us to improve runtime performance of produced binaries and support compiler caches for MinGW targets. Note that LLD requires import libraries for DLL linkage. Learn more in this Stack Overflow thread.


Kotlin/Native 1.6.0 delivers the following performance improvements:

  • Compilation time: compiler caches are enabled by default for linuxX64 and iosArm64 targets. This speeds up most compilations in debug mode (except the first one). Measurements showed about a 200% speed increase on our test projects. The compiler caches have been available for these targets since Kotlin 1.5.0 with additional Gradle properties; you can remove them now.
  • Runtime: iterating over arrays with for loops is now up to 12% faster thanks to optimizations in the produced LLVM code.

与 JVM 及 JS IR 后端统一编译器插件 ABI

The option to use the common IR compiler plugin ABI for Kotlin/Native is Experimental. It may be dropped or changed at any time. Opt-in is required (see details below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.

In previous versions, authors of compiler plugins had to provide separate artifacts for Kotlin/Native because of the differences in the ABI.

Starting from 1.6.0, the Kotlin Multiplatform Gradle plugin is able to use the embeddable compiler jar – the one used for the JVM and JS IR backends – for Kotlin/Native. This is a step toward unification of the compiler plugin development experience, as you can now use the same compiler plugin artifacts for Native and other supported platforms.

This is a preview version of such support, and it requires an opt-in. To start using generic compiler plugin artifacts for Kotlin/Native, add the following line to gradle.properties: kotlin.native.useEmbeddableCompilerJar=true.

We're planning to use the embeddable compiler jar for Kotlin/Native by default in the future, so it's vital for us to hear how the preview works for you.

If you are an author of a compiler plugin, please try this mode and check if it works for your plugin. Note that depending on your plugin's structure, migration steps may be required. See this YouTrack issue for migration instructions and leave your feedback in the comments.

klib 链接失败的详细错误信息

The Kotlin/Native compiler now provides detailed error messages for klib linkage errors. The messages now have clear error descriptions, and they also include information about possible causes and ways to fix them.

For example:

  • 1.5.30:

      e: java.lang.IllegalStateException: IrTypeAliasSymbol expected: Unbound public symbol for public kotlinx.coroutines/CancellationException|null[0]
      <stack trace>
  • 1.6.0:

      e: The symbol of unexpected type encountered during IR deserialization: IrClassPublicSymbolImpl, kotlinx.coroutines/CancellationException|null[0].
      IrTypeAliasSymbol is expected.
      This could happen if there are two libraries, where one library was compiled against the different version of the other library than the one currently used in the project.
      Please check that the project configuration is correct and has consistent versions of dependencies.
      The list of libraries that depend on "org.jetbrains.kotlinx:kotlinx-coroutines-core (org.jetbrains.kotlinx:kotlinx-coroutines-core-macosx64)" and may lead to conflicts:
      <list of libraries and potential version mismatches>
      Project dependencies:
      <dependencies tree>

重新设计了未处理异常的处理 API

We've unified the processing of unhandled exceptions throughout the Kotlin/Native runtime and exposed the default processing as the function processUnhandledException(throwable: Throwable) for use by custom execution environments, like kotlinx.coroutines. This processing is also applied to exceptions that escape operation in Worker.executeAfter(), but only for the new memory manager.

API improvements also affected the hooks that have been set by setUnhandledExceptionHook(). Previously such hooks were reset after the Kotlin/Native runtime called the hook with an unhandled exception, and the program would always terminate right after. Now these hooks may be used more than once, and if you want the program to always terminate on an unhandled exception, either do not set an unhandled exception hook (setUnhandledExceptionHook()), or make sure to call terminateWithUnhandledException() at the end of your hook. This will help you send exceptions to a third-party crash reporting service (like Firebase Crashlytics) and then terminate the program. Exceptions that escape main() and exceptions that cross the interop boundary will always terminate the program, even if the hook did not call terminateWithUnhandledException().


We're continuing to work on stabilizing the IR backend for the Kotlin/JS compiler. Kotlin/JS now has an 禁用下载 Node.js 与 Yarn 的选项.

可以选择使用预装的 Node.js 与 Yarn

You can now disable downloading Node.js and Yarn when building Kotlin/JS projects and use the instances already installed on the host. This is useful for building on servers without internet connectivity, such as CI servers.

To disable downloading external components, add the following lines to your build.gradle(.kts):

  • Yarn:


    rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
        rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().download = false // or true for default behavior


    rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin) {
        rootProject.extensions.getByType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension).download = false
  • Node.js:


    rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
        rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().download = false // or true for default behavior


    rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin) {
        rootProject.extensions.getByType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension).download = false

Kotlin Gradle 插件

In Kotlin 1.6.0, we changed the deprecation level of the KotlinGradleSubplugin class to 'ERROR'. This class was used for writing compiler plugins. In the following releases, we'll remove this class. Use the class KotlinCompilerPluginSupportPlugin instead.

We removed the kotlin.useFallbackCompilerSearch build option and the noReflect and includeRuntime compiler options. The useIR compiler option has been hidden and will be removed in upcoming releases.

Learn more about the currently supported compiler options in the Kotlin Gradle plugin.


The new 1.6.0 version of the standard library stabilizes experimental features, introduces new ones, and unifies its behavior across the platforms:

新版 readline 函数

Kotlin 1.6.0 offers new functions for handling standard input: readln() and readlnOrNull().

For now, new functions are available for the JVM and Native target platforms only.

Earlier versions 1.6.0 alternative Usage
readLine()!! readln() Reads a line from stdin and returns it, or throws a RuntimeException if EOF has been reached.
readLine() readlnOrNull() Reads a line from stdin and returns it, or returns null if EOF has been reached.

We believe that eliminating the need to use !! when reading a line will improve the experience for newcomers and simplify teaching Kotlin. To make the read-line operation name consistent with its println() counterpart, we've decided to shorten the names of new functions to 'ln'.

println("What is your nickname?")
val nickname = readln()
println("Hello, $nickname!")
fun main() {
    var sum = 0
    while (true) {
        val nextLine = readlnOrNull().takeUnless { 
        } ?: break
        sum += nextLine.toInt()

The existing readLine() function will get a lower priority than readln() and readlnOrNull() in your IDE code completion. IDE inspections will also recommend using new functions instead of the legacy readLine().

We're planning to gradually deprecate the readLine() function in future releases.

稳定版 typeOf()

Version 1.6.0 brings a Stable typeOf() function, closing one of the major roadmap items.

Since 1.3.40, typeOf() was available on the JVM platform as an experimental API. Now you can use it in any Kotlin platform and get KType representation of any Kotlin type that the compiler can infer:

inline fun <reified T> renderType(): String {
    val type = typeOf<T>()
    return type.toString()

fun main() {
    val fromExplicitType = typeOf<Int>()
    val fromReifiedType = renderType<List<Int>>()


In Kotlin 1.6.0, collection builder functions have been promoted to Stable. Collections returned by collection builders are now serializable in their read-only state.

You can now use buildMap(), buildList(), and buildSet() without the opt-in annotation:

fun main() {
    val x = listOf('b', 'c')
    val y = buildList {
    println(y)  // [a, b, c, d]

稳定版 Duration API

The Duration class for representing duration amounts in different time units has been promoted to Stable. In 1.6.0, the Duration API has received the following changes:

  • The first component of the toComponents() function that decomposes the duration into days, hours, minutes, seconds, and nanoseconds now has the Long type instead of Int. Before, if the value didn't fit into the Int range, it was coerced into that range. With the Long type, you can decompose any value in the duration range without cutting off the values that don't fit into Int.

  • The DurationUnit enum is now standalone and not a type alias of java.util.concurrent.TimeUnit on the JVM. We haven't found any convincing cases in which having typealias DurationUnit = TimeUnit could be useful. Also, exposing the TimeUnit API through a type alias might confuse DurationUnit users.

  • In response to community feedback, we're bringing back extension properties like Int.seconds. But we'd like to limit their applicability, so we put them into the companion of the Duration class. While the IDE can still propose extensions in completion and automatically insert an import from the companion, in the future we plan to limit this behavior to cases when the Duration type is expected.

    import kotlin.time.Duration.Companion.seconds
    fun main() {
        val duration = 10000
        println("There are ${duration.seconds.inWholeMinutes} minutes in $duration seconds")
        // There are 166 minutes in 10000 seconds

We suggest replacing previously introduced companion functions, such as Duration.seconds(Int), and deprecated top-level extensions like Int.seconds with new extensions in Duration.Companion.

Such a replacement may cause ambiguity between old top-level extensions and new companion extensions. Be sure to use the wildcard import of the kotlin.time package – import kotlin.time.* – before doing automated migration.

按 Regex 拆分为序列

The Regex.splitToSequence(CharSequence) and CharSequence.splitToSequence(Regex) functions are promoted to Stable. They split the string around matches of the given regex, but return the result as a Sequence so that all operations on this result are executed lazily:

fun main() {
    val colorsText = "green, red, brown&blue, orange, pink&green"
    val regex = "[,\\s]+".toRegex()
    val mixedColor = regex.splitToSequence(colorsText)
    // or
    // val mixedColor = colorsText.splitToSequence(regex)
        .onEach { println(it) }
        .firstOrNull { it.contains('&') }
    println(mixedColor) // "brown&blue"


In Kotlin 1.6.0, the rotateLeft() and rotateRight() functions for bit manipulations became Stable. The functions rotate the binary representation of the number left or right by a specified number of bits:

fun main() {
    val number: Short = 0b10001
        .toString(radix = 2)) // 100000000000100
        .toString(radix = 2))  // 1000100

JS 平台 replace() 与 replaceFirst() 的变更

Before Kotlin 1.6.0, the replace() and replaceFirst() Regex functions behaved differently in Java and JS when the replacement string contained a group reference. To make the behavior consistent across all target platforms, we've changed their implementation in JS.

Occurrences of ${name} or $index in the replacement string are substituted with the subsequences corresponding to the captured groups with the specified index or a name:

  • $index – the first digit after '$' is always treated as a part of the group reference. Subsequent digits are incorporated into the index only if they form a valid group reference.Only digits '0'–'9' are considered potential components of the group reference. Note that indexes of captured groups start from '1'. The group with index '0' stands for the whole match.
  • ${name} – the name can consist of Latin letters 'a'–'z', 'A'–'Z', or digits '0'–'9'. The first character must be a letter.

    Named groups in replacement patterns are currently supported only on the JVM.

  • To include the succeeding character as a literal in the replacement string, use the backslash character \:

      fun main() {
          println(Regex("(.+)").replace("Kotlin", """\$ $1""")) // $ Kotlin
          println(Regex("(.+)").replaceFirst("1.6.0", """\\ $1""")) // \ 1.6.0
You can use [`Regex.escapeReplacement()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/escape-replacement.html) if the replacement string has to be treated as a literal string.

既有 API 的改进

  • Version 1.6.0 added the infix extension function for Comparable.compareTo(). You can now use the infix form for comparing two objects for order:

       class WrappedText(val text: String) : Comparable<WrappedText> {
           override fun compareTo(other: WrappedText): Int =
               this.text compareTo other.text
  • Regex.replace() in JS is now also not inline to unify its implementation across all platforms.

  • The compareTo() and equals() String functions, as well as the isBlank() CharSequence function now behave in JS exactly the same way they do on the JVM. Previously there were deviations when it came to non-ASCII characters.


In Kotlin 1.6.0, we're starting the deprecation cycle with a warning for some JS-only stdlib API.

concat()、 match() 与 matches() 字符串函数

  • To concatenate the string with the string representation of a given other object, use plus() instead of concat().
  • To find all occurrences of a regular expression within the input, use findAll() of the Regex class instead of String.match(regex: String).
  • To check if the regular expression matches the entire input, use matches() of the Regex class instead of String.matches(regex: String).


We've deprecated the Array<out T>.sort() function and the inline functions ByteArray.sort(), ShortArray.sort(), IntArray.sort(), LongArray.sort(), FloatArray.sort(), DoubleArray.sort(), and CharArray.sort(), which sorted arrays following the order passed by the comparison function. Use other standard library functions for array sorting.

See the collection ordering section for reference.


Kover——Kotlin 的代码覆盖工具

The Kover Gradle plugin is Experimental. We would appreciate your feedback on it in GitHub.

With Kotlin 1.6.0, we're introducing Kover – a Gradle plugin for the IntelliJ and JaCoCo Kotlin code coverage agents. It works with all language constructs, including inline functions.

Learn more about Kover on its GitHub repository or in this video:

YouTube 视频:Kover – The Code Coverage Plugin

Coroutines 1.6.0-RC

kotlinx.coroutines 1.6.0-RC is out with multiple features and improvements:

  • Support for the new Kotlin/Native memory manager
  • Introduction of dispatcher views API, which allows limiting parallelism without creating additional threads
  • Migrating from Java 6 to Java 8 target
  • kotlinx-coroutines-test with the new reworked API and multiplatform support
  • Introduction of CopyableThreadContextElement, which gives coroutines a thread-safe write access to ThreadLocal variables

Learn more in the changelog.

迁移到 Kotlin 1.6.0

IntelliJ IDEA and Android Studio will suggest updating the Kotlin plugin to 1.6.0 once it is available.

To migrate existing projects to Kotlin 1.6.0, change the Kotlin version to 1.6.0 and reimport your Gradle or Maven project. Learn how to update to Kotlin 1.6.0.

To start a new project with Kotlin 1.6.0, update the Kotlin plugin and run the Project Wizard from File | New | Project.

The new command-line compiler is available for download on the GitHub release page.

Kotlin 1.6.0 is a feature release and can, therefore, bring changes that are incompatible with your code written for earlier versions of the language. Find the detailed list of such changes in the Compatibility Guide for Kotlin 1.6.