Kotlin Help

What's new in Kotlin 2.1.20-Beta2

Released: January 29, 2025

The Kotlin 2.1.20-Beta2 release is out! Here are some details of this EAP release:

IDE support

The Kotlin plugins that support 2.1.20-Beta2 are bundled in the latest IntelliJ IDEA and Android Studio. You don't need to update the Kotlin plugin in your IDE. All you need to do is to change the Kotlin version to 2.1.20-Beta2 in your build scripts.

See Update to a new release for details.

Kotlin K2 compiler: new default kapt plugin

Starting with Kotlin 2.1.20-Beta2, the K2 implementation of the kapt compiler plugin is enabled by default for all the projects.

The JetBrains team has launched the new implementation of the kapt plugin with the K2 compiler back in Kotlin 1.9.20. Since then, we have further developed K2 kapt's internal implementation and made its behavior similar to that of K1 kapt, while significantly improving its performance.

If you encounter any issues when using kapt with the K2 compiler, you can temporarily revert to the previous kapt plugin implementation.

To do this, add the following option to the gradle.properties file of your project:

kapt.use.k2=false

Please report such issues to our issue tracker.

Kotlin Multiplatform: new DSL to replace Gradle's Application plugin

Starting with Gradle 8.7, the Application plugin is no longer compatible with the Kotlin Multiplatform Gradle plugin. Kotlin 2.1.20-Beta2 introduces an Experimental DSL to achieve similar functionality. The new executable {} block configures execution tasks and Gradle distributions for JVM targets.

Before using the DSL, add the following to your build script:

@OptIn(ExperimentalKotlinGradlePluginApi::class)

Then, add the new executable {} block. For example:

kotlin { jvm { @OptIn(ExperimentalKotlinGradlePluginApi::class) binaries { // Configures a JavaExec task named "runJvm" and a Gradle distribution for the "main" compilation in this target executable { mainClass.set("foo.MainKt") } // Configures a JavaExec task named "runJvmAnother" and a Gradle distribution for the "main" compilation executable(KotlinCompilation.MAIN_COMPILATION_NAME, "another") { // Set a different class mainClass.set("foo.MainAnotherKt") } // Configures a JavaExec task named "runJvmTest" and a Gradle distribution for the "test" compilation executable(KotlinCompilation.TEST_COMPILATION_NAME) { mainClass.set("foo.MainTestKt") } // Configures a JavaExec task named "runJvmTestAnother" and a Gradle distribution for the "test" compilation executable(KotlinCompilation.TEST_COMPILATION_NAME, "another") { mainClass.set("foo.MainAnotherTestKt") } } } }

In this example, Gradle's Distribution plugin is applied on the first executable {} block.

If you run into any issues, report them in our issue tracker or let us know in our public Slack channel.

Gradle: support for version 8.11

Kotlin 2.1.20-Beta2 is now compatible with the latest stable Gradle version, 8.11, and supports its features. Gradle versions 8.7 to 8.11 are supported, with one exception. If you use the Kotlin Multiplatform Gradle plugin, you may see deprecation warnings in your multiplatform projects when calling the withJava() function in the JVM target. We plan to fix this issue as soon as possible.

For more information, see the related issue in YouTrack.

Standard library

Common atomic types

In Kotlin 2.1.20-Beta2, we are introducing common atomic types in the standard library's kotlin.concurrent.atomics package, enabling shared, platform-independent code for thread-safe operations. This simplifies development for Kotlin Multiplatform projects by removing the need to duplicate atomic-dependent logic across source sets.

The kotlin.concurrent.atomics package and its properties are Experimental. To opt in, use the @OptIn(ExperimentalAtomicApi::class) annotation or the compiler option -opt-in=kotlin.ExperimentalAtomicApi.

Here's an example that shows how you can use AtomicInt to safely count processed items across multiple threads:

// Imports the necessary libraries import kotlin.concurrent.atomics.* import kotlinx.coroutines.* //sampleStart @OptIn(ExperimentalAtomicApi::class) suspend fun main() { // Initializes the atomic counter for processed items 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) coroutineScope { for (chunk in itemChunks) { launch { for (item in chunk) { println("Processing $item in thread ${Thread.currentThread()}") processedItems += 1 // Increment counter atomically } } } } //sampleEnd // Prints the total number of processed items println("Total processed items: ${processedItems.load()}") }

To enable seamless interoperability between Kotlin's atomic types and Java's java.util.concurrent.atomic atomic types, the API provides the .asJavaAtomic() and .asKotlinAtomic() extension functions. On the JVM, Kotlin atomics and Java atomics are the same types in runtime, so you can transform Java atomics to Kotlin atomics and the other way around without any overhead.

Let's look at an example that shows how Kotlin and Java atomic types can work together:

// Imports the necessary libraries import kotlin.concurrent.atomics.* import java.util.concurrent.atomic.* //sampleStart @OptIn(ExperimentalAtomicApi::class) fun main() { // Converts Kotlin AtomicInt to Java's AtomicInteger val kotlinAtomic = AtomicInt(42) val javaAtomic: AtomicInteger = kotlinAtomic.asJavaAtomic() println("Java atomic value: ${javaAtomic.get()}") // Java atomic value: 42 // Converts Java's AtomicInteger back to Kotlin's AtomicInt val kotlinAgain: AtomicInt = javaAtomic.asKotlinAtomic() println("Kotlin atomic value: ${kotlinAgain.load()}") // Kotlin atomic value: 42 } //sampleEnd

Changes in UUID parsing and formatting functions

The JetBrains team continues to improve the support for UUIDs introduced to the standard library in 2.0.20.

Previously, the parse() function only accepted UUIDs in the hex-and-dash format. With Kotlin 2.1.20-Beta2, you can use parse() for both the hex-and-dash and the plain hexadecimal format (without dashes).

We also introduce functions specific to the operations with the hex-and-dash format in this release:

  • parseHexDash() that parses UUIDs from the hex-and-dash format.

  • toHexDashString() that converts a UUID into a string in the hex-and-dash format (mirroring the toString() functionality).

These functions work similarly to parseHex() and toHexString() that were introduced earlier for the hexadecimal format. Explicit naming for the parsing and formatting functionality should improve code clarity and your overall experience with UUID handling.

Remember that the UUID support in the standard library is still Experimental. To opt in, use the @ExperimentalUuidApi annotation or the compiler option -opt-in=kotlin.uuid.ExperimentalUuidApi:

import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid //sampleStart @OptIn(ExperimentalUuidApi::class) fun main() { // Use parse() to accept a UUID in a plain hexadecimal format val uuid = Uuid.parse("550e8400e29b41d4a716446655440000") // Convert it to the hex-and-dash format val hexDashFormat = uuid.toHexDashString() println(hexDashFormat) // Output: 550e8400-e29b-41d4-a716-446655440000 } //sampleEnd

How to update to Kotlin 2.1.20-Beta2

Starting from IntelliJ IDEA 2023.3 and Android Studio Iguana (2023.2.1) Canary 15, the Kotlin plugin is distributed as a bundled plugin included in your IDE. This means that you can't install the plugin from JetBrains Marketplace anymore. The bundled plugin supports upcoming Kotlin EAP releases.

To update to the new Kotlin EAP version, change the Kotlin version to 2.1.20-Beta2 in your build scripts.

Last modified: 29 January 2025