Spec-Zone.ru › Kotlin 2

Что нового в Kotlin 2.2.20

Выпуск: 10 сентября 2025 г.

Вышел Kotlin 2.2.20 с важными изменениями для веб-разработки. Kotlin/Wasm теперь в статусе Beta. В этом выпуске улучшена обработка исключений при взаимодействии с JavaScript, управление зависимостями npm, добавлена встроенная поддержка отладки в браузере и новый общий набор исходного кода для целей js и wasmJs.

Кроме того, вот некоторые основные нововведения:

  • Kotlin Multiplatform: экспорт в Swift доступен по умолчанию, стабильная кроссплатформенная компиляция библиотек Kotlin и новый способ объявления общих зависимостей.

  • Язык: улучшено разрешение перегрузок при передаче лямбд в перегруженные функции с типами suspend-функций.

  • Kotlin/Native: поддержка Xcode 26, защита стека и уменьшенный размер бинарных файлов для релизных сборок.

  • Kotlin/JS: значения Long компилируются в JavaScript как BigInt.

Compose Multiplatform для веба переходит в статус Beta. Подробнее — в нашей публикации в блоге.

Краткий обзор обновлений также представлен в этом видео:

Информацию о цикле выпуска Kotlin см. в разделе Процесс выпуска Kotlin.

Поддержка IDE

Плагин Kotlin с поддержкой Kotlin 2.2.20 входит в состав последних версий IntelliJ IDEA и Android Studio. Чтобы обновить его, достаточно изменить версию Kotlin на 2.2.20 в сценариях сборки.

Подробнее см. в разделе Обновление до нового выпуска.

Язык

В Kotlin 2.2.20 можно попробовать новые языковые функции, запланированные для Kotlin 2.3.0, в том числе улучшенное разрешение перегрузок при передаче лямбд в перегруженные функции с типами suspend-функций и поддержку операторов return в телах-выражениях с явно указанными типами возвращаемых значений. В этом выпуске также улучшены проверки полноты выражений when, перехват reified-типов Throwable и контракты Kotlin.

Улучшенное разрешение перегрузок для лямбд с типами suspend-функций

Ранее перегрузка функции вариантами с обычным типом функции и типом suspend-функции приводила к ошибке неоднозначности при передаче лямбды. Эту ошибку можно было обойти с помощью явного приведения типа, но компилятор ошибочно выдавал предупреждение No cast needed:

// Defines two overloads
fun transform(block: () -> Int) {}
fun transform(block: suspend () -> Int) {}

fun test() {
    // Fails with overload resolution ambiguity
    transform({ 42 })

    // Uses an explicit cast, but the compiler incorrectly reports 
    // a "No cast needed" warning
    transform({ 42 } as () -> Int)
}

Теперь, если определить перегрузки с обычным типом функции и типом suspend-функции, лямбда без приведения типа будет разрешаться в обычную перегрузку. Используйте ключевое слово suspend, чтобы явно выбрать перегрузку с suspend:

// Resolves to transform(() -> Int)
transform({ 42 })

// Resolves to transform(suspend () -> Int)
transform(suspend { 42 })

По умолчанию это поведение будет включено в Kotlin 2.3.0. Чтобы проверить его уже сейчас, установите версию языка 2.3 с помощью следующего параметра компилятора:

-language-version 2.3

Либо настройте его в файле build.gradle(.kts):

kotlin {
    compilerOptions {
        languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3)
    }
}

Будем признательны за ваши отзывы в нашем трекере задач — YouTrack.

Поддержка операторов return в телах-выражениях с явно указанными типами возвращаемых значений

Ранее использование return в теле-выражении вызывало ошибку компилятора, поскольку тип возвращаемого значения функции мог выводиться как Nothing.

fun example() = return 42
// Error: Returns are prohibited for functions with an expression body

Теперь можно использовать return в телах-выражениях, если тип возвращаемого значения указан явно:

// Specifies the return type explicitly
fun getDisplayNameOrDefault(userId: String?): String = getDisplayName(userId ?: return "default")

// Fails because it doesn't specify the return type explicitly
fun getDisplayNameOrDefault(userId: String?) = getDisplayName(userId ?: return "default")

Аналогично, операторы return внутри лямбд и вложенных выражений в функциях с телами-выражениями раньше компилировались непреднамеренно. Теперь Kotlin поддерживает такие случаи, если тип возвращаемого значения указан явно. Случаи без явно заданного типа возвращаемого значения будут объявлены устаревшими в Kotlin 2.3.0:

// Return type isn't explicitly specified, and the return statement is inside a lambda
// which will be deprecated
fun returnInsideLambda() = run { return 42 }

// Return type isn't explicitly specified, and the return statement is inside the initializer
// of a local variable, which will be deprecated
fun returnInsideIf() = when {
    else -> {
        val result = if (someCondition()) return "" else "value"
        result
    }
}

По умолчанию это поведение будет включено в Kotlin 2.3.0. Чтобы проверить его уже сейчас, установите версию языка 2.3 с помощью следующего параметра компилятора:

-language-version 2.3

Либо настройте его в файле build.gradle(.kts):

kotlin {
    compilerOptions {
        languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3)
    }
}

Будем признательны за ваши отзывы в нашем трекере задач — YouTrack.

Проверки полноты выражений when на основе потока данных

В Kotlin 2.2.20 появились проверки полноты выражений when на основе потока данных. Ранее проверки компилятора ограничивались самим выражением when, из-за чего часто приходилось добавлять избыточную ветвь else. Теперь компилятор отслеживает предыдущие проверки условий и ранние возвраты, поэтому можно удалить избыточные ветви else.

Например, теперь компилятор распознает, что функция возвращает значение при выполнении условия if, поэтому выражению when достаточно обрабатывать только оставшиеся случаи:

enum class UserRole { ADMIN, MEMBER, GUEST }

fun getPermissionLevel(role: UserRole): Int {
    // Covers the Admin case outside of the when expression
    if (role == UserRole.ADMIN) return 99

    return when (role) {
        UserRole.MEMBER -> 10
        UserRole.GUEST -> 1
        // You no longer have to include this else branch 
        // else -> throw IllegalStateException()
    }
}

Эта функция является экспериментальной. Чтобы включить ее, добавьте следующий параметр компилятора в файл build.gradle(.kts):

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xdata-flow-based-exhaustiveness")
    }
}

Поддержка reified-типов в блоках catch

В Kotlin 2.2.20 компилятор теперь разрешает использовать reified-параметры обобщенного типа в блоках catch функций inline.

Пример:

inline fun <reified ExceptionType : Throwable> handleException(block: () -> Unit) {
    try {
        block()
        // This is now allowed after the change
    } catch (e: ExceptionType) {
        println("Caught specific exception: ${e::class.simpleName}")
    }
}

fun main() {
    // Tries to perform an action that might throw an IOException
    handleException<java.io.IOException> {
        throw java.io.IOException("File not found")
    }
    // Caught specific exception: IOException
}

Ранее попытка перехватить reified-тип Throwable в функции inline приводила к ошибке.

По умолчанию это поведение будет включено в Kotlin 2.4.0. Чтобы использовать его уже сейчас, добавьте следующий параметр компилятора в файл build.gradle(.kts):

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xallow-reified-type-in-catch")
    }
}

Команда Kotlin благодарит стороннего участника Ивена Кралла за его вклад.

Улучшенные контракты Kotlin

В Kotlin 2.2.20 появилось несколько улучшений контрактов Kotlin, в том числе:

  • поддержка обобщений в проверках типов в контрактах.

  • поддержка контрактов в аксессорах свойств и некоторых операторных функциях.

  • поддержка функции returnsNotNull() в контрактах, которая позволяет гарантировать ненулевое возвращаемое значение при выполнении условия.

  • новое ключевое слово holdsIn, позволяющее считать условия истинными, если они переданы внутрь лямбд.

Эти улучшения являются экспериментальными. Для их использования при объявлении контрактов по-прежнему необходимо указывать аннотацию @OptIn(ExperimentalContracts::class). Ключевое слово holdsIn и функция returnsNotNull() также требуют аннотации @OptIn(ExperimentalExtendedContracts::class).

Чтобы воспользоваться этими улучшениями, также необходимо добавить параметры компилятора, описанные в разделах ниже.

Будем признательны за ваши отзывы в нашем трекере задач.

Поддержка обобщений в проверках типов в контрактах

Теперь можно писать контракты, проверяющие типы обобщенных типов:

import kotlin.contracts.*

sealed class Failure {
    class HttpError(val code: Int) : Failure()
    // Insert other failure types here
}

sealed class Result<out T, out F : Failure> {
    class Success<T>(val data: T) : Result<T, Nothing>()
    class Failed<F : Failure>(val failure: F) : Result<Nothing, F>()
}

@OptIn(ExperimentalContracts::class)
// Uses a contract to assert a generic type
fun <T, F : Failure> Result<T, F>.isHttpError(): Boolean {
    contract {
        returns(true) implies (this@isHttpError is Result.Failed<Failure.HttpError>)
    }
    return this is Result.Failed && this.failure is Failure.HttpError
}

В этом примере контракт проверяет тип объекта Result, позволяя компилятору безопасно выполнить для него умное приведение типа к проверяемому обобщенному типу.

Эта функция является экспериментальной. Чтобы использовать ее, добавьте следующий параметр компилятора в файл build.gradle(.kts):

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xallow-contracts-on-more-functions")
    }
}

Поддержка контрактов в аксессорах свойств и некоторых операторных функциях

Теперь можно определять контракты в аксессорах свойств и некоторых операторных функциях. Это позволяет использовать контракты в большем количестве типов объявлений и делает их более гибкими.

Например, контракт в геттере можно использовать для умного приведения типа объекта-получателя:

import kotlin.contracts.*

val Any.isHelloString: Boolean
    get() {
        @OptIn(ExperimentalContracts::class)
        // Enables smart casting the receiver to String when the getter returns true
        contract { returns(true) implies (this@isHelloString is String) }
        return "hello" == this
    }

fun printIfHelloString(x: Any) {
    if (x.isHelloString) {
        // Prints the length after the smart cast of the receiver to String
        println(x.length)
        // 5
    }
}

Кроме того, контракты можно использовать в следующих операторных функциях:

  • invoke

  • contains

  • rangeTo, rangeUntil

  • componentN

  • iterator

  • unaryPlus, unaryMinus, not

  • inc, dec

Вот пример использования контракта в операторной функции для гарантии инициализации переменной внутри лямбды:

import kotlin.contracts.*

class Runner {
    @OptIn(ExperimentalContracts::class)
    // Enables initialization of variables assigned inside the lambda
    operator fun invoke(block: () -> Unit) {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        block()
    }
}

fun testOperator(runner: Runner) {
    val number: Int
    runner {
        number = 1
    }
    // Prints the value after definite initialization guaranteed by the contract
    println(number)
    // 1
}

Эта функция является экспериментальной. Чтобы использовать ее, добавьте следующий параметр компилятора в файл build.gradle(.kts):

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xallow-contracts-on-more-functions")
    }
}

Поддержка функции returnsNotNull() в контрактах

В Kotlin 2.2.20 появилась функция returnsNotNull() для контрактов. Ее можно использовать, чтобы гарантировать возврат функцией ненулевого значения при выполнении определенного условия. Это упрощает код: вместо отдельных перегрузок функций для nullable- и non-nullable-значений можно использовать одну лаконичную функцию:

import kotlin.contracts.*

@OptIn(ExperimentalContracts::class, ExperimentalExtendedContracts::class)
fun decode(encoded: String?): String? {
    contract {
        // Guarantees a non-null return value when the input is non-null
        (encoded != null) implies (returnsNotNull())
    }
    if (encoded == null) return null
    return java.net.URLDecoder.decode(encoded, "UTF-8")
}

fun useDecodedValue(s: String?) {
    // Uses a safe call since the return value may be null
    decode(s)?.length
    if (s != null) {
        // Treats the return value as non-null after the smart cast
        decode(s).length
    }
}

В этом примере контракт функции decode() позволяет компилятору выполнить умное приведение типа возвращаемого значения, если входное значение не равно null. Это избавляет от необходимости в дополнительных проверках на null или нескольких перегрузках.

Эта функция является экспериментальной. Чтобы использовать ее, добавьте следующий параметр компилятора в файл build.gradle(.kts):

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xallow-condition-implies-returns-contracts")
    }
}

Новое ключевое слово holdsIn

В Kotlin 2.2.20 появилось новое ключевое слово holdsIn для контрактов. С его помощью можно гарантировать, что внутри определенной лямбды логическое условие считается true. Это позволяет создавать DSL с условными умными приведениями типов с помощью контрактов.

Пример:

import kotlin.contracts.*

@OptIn(ExperimentalContracts::class, ExperimentalExtendedContracts::class)
fun <T> T.alsoIf(condition: Boolean, block: (T) -> Unit): T {
    contract {
        // Declares that the lambda runs at most once
        callsInPlace(block, InvocationKind.AT_MOST_ONCE)
        // Declares that the condition is assumed to be true inside the lambda
        condition holdsIn block
    }
    if (condition) block(this)
    return this
}

fun useApplyIf(input: Any) {
    val result = listOf(1, 2, 3)
        .first()
        .alsoIf(input is Int) {
            // The input parameter is smart cast to Int inside the lambda
            // Prints the sum of input and first list element
            println(input + it)
            // 2
        }
        .toString()
}

Эта функция является экспериментальной. Чтобы использовать ее, добавьте следующий параметр компилятора в файл build.gradle(.kts):

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xallow-holdsin-contract")
    }
}

Kotlin/JVM: поддержка invokedynamic с выражениями when

В Kotlin 2.2.20 теперь можно компилировать выражения when с помощью invokedynamic. Ранее выражения when с несколькими проверками типов компилировались в длинную цепочку проверок instanceof в байт-коде.

Теперь можно использовать invokedynamic с выражениями when, чтобы создавать более компактный байт-код, аналогичный байт-коду, генерируемому операторами switch в Java, если выполняются следующие условия:

  • Все условия, кроме else, являются проверками is или null.

  • Выражение не содержит условий-охранников (if).

  • Условия не включают типы, которые нельзя проверить напрямую, например изменяемые коллекции Kotlin (MutableList) или функциональные типы (kotlin.Function1, kotlin.Function2 и т. д.).

  • Помимо else есть как минимум два условия.

  • Во всех ветвях проверяется одна и та же тема выражения when.

Например:

open class Example

class A : Example()
class B : Example()
class C : Example()

fun test(e: Example) = when (e) {
    // Uses invokedynamic with SwitchBootstraps.typeSwitch
    is A -> 1
    is B -> 2
    is C -> 3
    else -> 0
}

Если включить новую функцию, выражение when в этом примере будет компилироваться в единый переключатель типов invokedynamic вместо нескольких проверок instanceof.

Чтобы включить эту функцию, скомпилируйте код Kotlin с целевой платформой JVM 21 или выше и добавьте следующий параметр компилятора:

-Xwhen-expressions=indy

Либо добавьте его в блок compilerOptions {} файла build.gradle(.kts):

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xwhen-expressions=indy")
    }
}

Эта функция является экспериментальной. Будем признательны за ваши отзывы в нашем трекере задач — YouTrack.

Kotlin Multiplatform

В Kotlin 2.2.20 появились значительные изменения для Kotlin Multiplatform: экспорт Swift доступен по умолчанию, добавлен новый общий исходный набор, а также можно попробовать новый подход к управлению общими зависимостями.

Экспорт Swift доступен по умолчанию

В Kotlin 2.2.20 появилась экспериментальная поддержка экспорта Swift. Она позволяет экспортировать исходный код Kotlin напрямую и вызывать код Kotlin из Swift привычным образом, устраняя необходимость в заголовках Objective-C.

Это должно значительно улучшить многоплатформенную разработку для целевых платформ Apple. Например, если у вас есть модуль Kotlin с функциями верхнего уровня, экспорт Swift позволяет использовать понятные импорты для каждого модуля, избавляя от сбивающих с толку подчёркиваний Objective-C и искажённых имён.

Ключевые возможности:

  • Поддержка нескольких модулей. Каждый модуль Kotlin экспортируется как отдельный модуль Swift, что упрощает вызов функций.

  • Поддержка пакетов. Пакеты Kotlin явно сохраняются при экспорте, что позволяет избежать конфликтов имён в сгенерированном коде Swift.

  • Псевдонимы типов. Псевдонимы типов Kotlin экспортируются и сохраняются в Swift, что повышает удобочитаемость.

  • Расширенная поддержка null для примитивных типов. В отличие от взаимодействия с Objective-C, где для сохранения возможности null требовалось помещать типы, такие как Int?, в классы-обёртки, например KotlinInt, экспорт Swift преобразует информацию о возможности null напрямую.

  • Перегрузки. Вы можете вызывать перегруженные функции Kotlin в Swift без неоднозначности.

  • Уплощённая структура пакетов. Вы можете преобразовать пакеты Kotlin в перечисления Swift, удалив префикс пакета из сгенерированного кода Swift.

  • Настройка имени модуля. Вы можете настроить имена результирующих модулей Swift в конфигурации Gradle проекта Kotlin.

Как включить экспорт Swift

В настоящее время эта возможность имеет статус экспериментальной и работает только в проектах, использующих прямую интеграцию для подключения фреймворка iOS к проекту Xcode. Это стандартная конфигурация для многоплатформенных проектов, созданных с помощью плагина Kotlin Multiplatform в IntelliJ IDEA или через веб-мастер.

Чтобы попробовать экспорт Swift, настройте проект Xcode:

  1. В Xcode откройте настройки проекта.

  2. На вкладке Build Phases найдите этап Run Script с задачей embedAndSignAppleFrameworkForXcode.

  3. Измените скрипт, указав вместо него задачу embedSwiftExportForXcode на этапе выполнения скрипта:

    ./gradlew :<Shared module name>:embedSwiftExportForXcode
    
    Add the Swift export script
  4. Соберите проект. Модули Swift будут созданы в каталоге выходных данных сборки.

Эта возможность доступна по умолчанию. Если вы уже включили её в предыдущих версиях, теперь можно удалить kotlin.experimental.swift-export.enabled из файла gradle.properties.

Чтобы сэкономить время, клонируйте наш общедоступный пример, в котором экспорт Swift уже настроен.

Дополнительные сведения об экспорте Swift см. в нашей документации.

Оставить отзыв

В будущих выпусках Kotlin мы планируем расширять поддержку экспорта Swift и постепенно повышать её стабильность. После выхода Kotlin 2.2.20 мы сосредоточимся на улучшении взаимодействия Kotlin и Swift, особенно в части корутин и потоков данных.

Поддержка экспорта Swift — значительное изменение для Kotlin Multiplatform. Мы будем признательны за ваши отзывы:

  • Свяжитесь напрямую с командой разработчиков в Kotlin Slack: получите приглашение и присоединитесь к каналу #swift-export.

  • Сообщайте о проблемах с экспортом Swift в YouTrack.

Общий исходный набор для целевых платформ js и wasmJs

Ранее Kotlin Multiplatform по умолчанию не включал общий исходный набор для веб-целевых платформ JavaScript (js) и WebAssembly (wasmJs). Чтобы совместно использовать код между js и wasmJs, нужно было вручную настроить пользовательский исходный набор или написать код в двух местах: одну версию для js и другую для wasmJs. Например:

// commonMain
expect suspend fun readCopiedText(): String

// jsMain
external interface Navigator { val clipboard: Clipboard }
// Different interop in JS and Wasm
external interface Clipboard { fun readText(): Promise<String> }
external val navigator: Navigator

suspend fun readCopiedText(): String {
    // Different interop in JS and Wasm
    return navigator.clipboard.readText().await()
}

// wasmJsMain
external interface Navigator { val clipboard: Clipboard }
external interface Clipboard { fun readText(): Promise<JsString> }
external val navigator: Navigator

suspend fun readCopiedText(): String {
    return navigator.clipboard.readText().await().toString()
}

Начиная с этого выпуска, плагин Kotlin Gradle добавляет новый общий исходный набор для веба (включающий webMain и webTest), если вы используете шаблон иерархии по умолчанию.

После этого изменения исходный набор web становится родительским для обоих исходных наборов: js и wasmJs. Обновлённая иерархия исходных наборов выглядит так:

An example of using the default hierarchy template with web

Новый исходный набор позволяет написать один фрагмент кода для обеих целевых платформ: js и wasmJs. Поместите общий код в webMain, и он автоматически будет работать на обеих платформах:

// commonMain
expect suspend fun readCopiedText(): String

// webMain
@OptIn(ExperimentalWasmJsInterop::class)
private suspend fun <R : JsAny?> Promise<R>.await(): R = suspendCancellableCoroutine { continuation ->
    this.then(
        onFulfilled = { continuation.resumeWith(Result.success(it)); null },
        onRejected = { continuation.resumeWithException(it.asJsException()); null }
    )
}

external interface Navigator { val clipboard: Clipboard }
external interface Clipboard { fun readText(): Promise<JsString> }
external val navigator: Navigator

actual suspend fun readCopiedText(): String {
    return navigator.clipboard.readText().await().toString()
}

Это обновление упрощает совместное использование кода между целевыми платформами js и wasmJs. Оно особенно полезно в двух случаях:

  • Если вы разрабатываете библиотеку и хотите добавить поддержку целевых платформ js и wasmJs без дублирования кода.

  • Если вы разрабатываете приложения Compose Multiplatform для веба и хотите включить кросс-компиляцию для целевых платформ js и wasmJs, чтобы обеспечить совместимость с большим числом браузеров. Благодаря такому резервному режиму созданный веб-сайт будет работать во всех браузерах сразу: современные браузеры используют wasmJs, а более старые — js.

Чтобы попробовать эту возможность, используйте шаблон иерархии по умолчанию в блоке kotlin {} файла build.gradle(.kts):

kotlin {
    js()
    wasmJs()

    // Enables the default source set hierarchy, including webMain and webTest
    applyDefaultHierarchyTemplate()
}

Перед использованием иерархии по умолчанию тщательно оцените возможные конфликты, если в проекте есть пользовательский общий исходный набор или если вы переименовали целевую платформу js("web"). Чтобы устранить эти конфликты, переименуйте конфликтующий исходный набор или целевую платформу либо не используйте иерархию по умолчанию.

Стабильная кросс-компиляция для библиотек Kotlin

В Kotlin 2.2.20 завершён важный пункт дорожной карты: кросс-компиляция для библиотек Kotlin стала стабильной.

Теперь можно использовать любой поддерживаемый хост для создания артефактов .klib и публикации библиотек Kotlin. Это значительно упрощает процесс публикации, особенно для целевых платформ Apple, для которых раньше требовался компьютер Mac.

Эта возможность доступна по умолчанию. Если вы уже включили кросс-компиляцию с помощью kotlin.native.enableKlibsCrossCompilation=true, теперь можно удалить её из файла gradle.properties.

К сожалению, некоторые ограничения всё ещё действуют. Компьютер Mac по-прежнему нужен, если:

  • Ваша библиотека или любой из зависимых модулей содержит зависимости cinterop.

  • В проекте настроена интеграция с CocoaPods.

  • Необходимо собрать или протестировать итоговые бинарные файлы для целевых платформ Apple.

Дополнительные сведения о публикации многоплатформенных библиотек см. в нашей документации.

Новый подход к объявлению общих зависимостей

Чтобы упростить настройку многоплатформенных проектов с помощью Gradle, в Kotlin 2.2.20 появилась возможность объявлять общие зависимости в блоке kotlin {} с помощью блока верхнего уровня dependencies {}, если в проекте используется Gradle 8.8 или более поздней версии. Эти зависимости работают так, как если бы они были объявлены в исходном наборе commonMain. Эта возможность работает аналогично блоку зависимостей для проектов только с Kotlin/JVM или Android и теперь имеет статус экспериментальной в Kotlin Multiplatform.

Объявление общих зависимостей на уровне проекта сокращает повторение конфигурации в исходных наборах и упрощает настройку сборки. При необходимости вы по-прежнему можете добавлять зависимости для конкретных платформ в каждый исходный набор.

Чтобы попробовать эту возможность, примите участие в эксперименте, добавив аннотацию @OptIn(ExperimentalKotlinGradlePluginApi::class) перед блоком верхнего уровня dependencies {}. Например:

kotlin {
    @OptIn(ExperimentalKotlinGradlePluginApi::class)
    dependencies {
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0")
    }
}

Мы будем признательны за ваши отзывы об этой возможности в YouTrack.

Новая диагностика поддержки целевых платформ в зависимостях

До Kotlin 2.2.20, если зависимость в скрипте сборки не поддерживала все целевые платформы, необходимые исходному набору, сообщения об ошибках Gradle затрудняли понимание проблемы.

В Kotlin 2.2.20 появилась новая диагностика, которая наглядно показывает, какие целевые платформ поддерживает каждая зависимость, а какие — нет.

Эта диагностика включена по умолчанию. Если по какой-либо причине её нужно отключить, сообщите нам об этом в комментарии к этой задаче в YouTrack. Чтобы отключить диагностику, можно использовать следующие свойства Gradle в файле gradle.properties:

Свойство

Описание

kotlin.kmp.eagerUnresolvedDependenciesDiagnostic=false

Запускает диагностику только для компиляций и импортов метаданных

kotlin.kmp.unresolvedDependenciesDiagnostic=false

Полностью отключает диагностику

Kotlin/Native

В этом выпуске добавлена поддержка Xcode 26, улучшена совместимость с Objective-C/Swift и отладка, а также появились новые параметры бинарных файлов.

Поддержка Xcode 26

Начиная с Kotlin 2.2.21, компилятор Kotlin/Native поддерживает Xcode 26 — последнюю стабильную версию Xcode. Теперь можно обновить Xcode и получить доступ к новейшим API, чтобы продолжить работу над проектами Kotlin для операционных систем Apple.

Поддержка стековых канареек в бинарных файлах

Начиная с Kotlin 2.2.20, Kotlin поддерживает стековые канарейки в результирующих бинарных файлах Kotlin/Native. Эта функция безопасности защищает стек от повреждения в рамках защиты стека и помогает снизить риск некоторых распространённых уязвимостей приложений. Такая возможность уже была доступна в Swift и Objective-C, теперь она поддерживается и в Kotlin.

Реализация защиты стека в Kotlin/Native соответствует поведению защиты стека в Clang.

Чтобы включить стековые канарейки, добавьте следующий параметр бинарного файла в файл gradle.properties:

kotlin.native.binary.stackProtector=yes

Это свойство включает функцию для всех функций Kotlin, уязвимых к повреждению стека. Доступны следующие альтернативные режимы:

  • kotlin.native.binary.stackProtector=strong — использует более строгую эвристику для функций, уязвимых к повреждению стека.

  • kotlin.native.binary.stackProtector=all — включает защиту стека для всех функций.

Обратите внимание, что в некоторых случаях защита стека может снизить производительность.

Уменьшение размера бинарных файлов для выпуска

В Kotlin 2.2.20 появился параметр smallBinary, который позволяет уменьшить размер бинарных файлов для выпуска. Новый параметр фактически задаёт -Oz в качестве аргумента оптимизации компилятора по умолчанию на этапе компиляции LLVM.

При включённом параметре smallBinary можно уменьшить размер бинарных файлов для выпуска и ускорить сборку. Однако в некоторых случаях это может повлиять на производительность во время выполнения.

Новая возможность пока имеет статус экспериментальной. Чтобы попробовать её в проекте, добавьте следующий параметр бинарного файла в файл gradle.properties:

kotlin.native.binary.smallBinary=true

Команда Kotlin благодарит Трульса Лунда за помощь в реализации этой возможности.

Улучшенное отображение объектов в отладчике

Теперь Kotlin/Native формирует более понятные описания объектов для таких средств отладки, как LLDB и GDB. Это повышает удобочитаемость получаемой отладочной информации и упрощает отладку.

Рассмотрим, например, следующий объект:

class Point(val x: Int, val y: Int)
val point = Point(1, 2)

Ранее при просмотре отображалась лишь ограниченная информация, включая указатель на адрес памяти объекта:

(lldb) v point
(ObjHeader *) point = [x: ..., y: ...]
(lldb) v point->x
(int32_t *) x = 0x0000000100274048

В Kotlin 2.2.20 отладчик теперь показывает больше сведений, включая фактические значения:

(lldb) v point
(ObjHeader *) point = Point(x=1, y=2)
(lldb) v point->x
(int32_t) point->x = 1

Команда Kotlin благодарит Никиту Назарова за помощь в реализации этой возможности.

Дополнительные сведения об отладке в Kotlin/Native см. в документации.

Явные имена в типах блоков для заголовков Objective-C

В Kotlin 2.2.20 появилась возможность добавлять явные имена параметров к типам функций Kotlin в заголовках Objective-C, экспортируемых из проектов Kotlin/Native. Имена параметров улучшают подсказки автодополнения в Xcode и помогают избежать предупреждений Clang.

Ранее имена параметров в типах блоков не указывались в сгенерированных заголовках Objective-C. В таких случаях автодополнение Xcode предлагало вызывать эти функции без имён параметров в блоке Objective-C. Сгенерированный блок вызывал предупреждения Clang.

Например, для следующего кода Kotlin:

// Kotlin:
fun greetUser(block: (name: String) -> Unit) = block("John")

В сгенерированном заголовке Objective-C отсутствовало имя параметра:

// Objective-C:
+ (void)greetUserBlock:(void (^)(NSString *))block __attribute__((swift_name("greetUser(block:)")));

Поэтому при вызове функции greetUserBlock() из Objective-C в Xcode среда разработки предлагала такой вариант:

// Objective-C:
greetUserBlock:^(NSString *) {
    // ...
};

Отсутствующее имя параметра (NSString *) в подсказке вызывало предупреждения Clang.

С новым параметром Kotlin передаёт имена параметров из типов функций Kotlin в типы блоков Objective-C, поэтому Xcode использует их в подсказках:

// Objective-C:
greetUserBlock:^(NSString *name) {
    // ...
};

Чтобы включить явные имена параметров, добавьте следующий параметр бинарного файла в файл gradle.properties:

kotlin.native.binary.objcExportBlockExplicitParameterNames=true

Команда Kotlin благодарит Ицзе Цзяна за реализацию этой возможности.

Уменьшение размера дистрибутива Kotlin/Native

Ранее дистрибутив Kotlin/Native содержал два JAR-файла с кодом компилятора:

  • konan/lib/kotlin-native.jar

  • konan/lib/kotlin-native-compiler-embeddable.jar.

Начиная с Kotlin 2.2.20, kotlin-native.jar больше не публикуется.

Удалённый JAR-файл содержит устаревшую версию встраиваемого компилятора, которая больше не требуется. Это изменение значительно уменьшает размер дистрибутива.

В результате следующие параметры устарели и были удалены:

  • Свойство Gradle kotlin.native.useEmbeddableCompilerJar=false. Вместо него в проектах Kotlin/Native всегда используется JAR-файл встраиваемого компилятора.

  • Функция KotlinCompilerPluginSupportPlugin.getPluginArtifactForNative(). Вместо неё всегда используется функция getPluginArtifact().

Дополнительные сведения см. в задаче в YouTrack.

Экспорт KDoc в заголовки Objective-C по умолчанию

Комментарии KDoc теперь экспортируются по умолчанию при создании заголовков Objective-C во время компиляции итоговых бинарных файлов Kotlin/Native.

Ранее требовалось вручную добавлять параметр -Xexport-kdoc в файл сборки. Теперь он автоматически передаётся задачам компиляции.

Этот параметр встраивает комментарии KDoc в klib и извлекает комментарии из klib при создании фреймворков Apple. В результате комментарии к классам и методам отображаются, например, при автодополнении в Xcode.

Экспорт комментариев KDoc из klib в создаваемые фреймворки Apple можно отключить в блоке binaries {} файла build.gradle(.kts):

import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi

kotlin {
    iosArm64 {
        binaries {
            framework { 
                baseName = "sdk"
                @OptIn(ExperimentalKotlinGradlePluginApi::class)
                exportKdoc.set(false)
            }
        }
    }
}

Дополнительные сведения см. в нашей документации.

Устаревание целевых платформ Apple x86_64

Apple перестала выпускать устройства с чипами Intel несколько лет назад и недавно объявила, что macOS Tahoe 26 станет последней версией ОС с поддержкой архитектуры Intel.

Из-за этого нам всё сложнее корректно тестировать эти целевые платформы на наших агентах сборки, особенно в будущих выпусках Kotlin, где мы обновим поддерживаемую версию Xcode, поставляемую с macOS 26.

Начиная с Kotlin 2.2.20, целевые платформы macosX64 и iosX64 переведены на уровень поддержки 2. Это означает, что они регулярно тестируются в CI на предмет успешной компиляции, но автоматическая проверка их работоспособности может не выполняться.

Мы планируем постепенно объявить устаревшими все целевые платформы Apple x86_64 и в конечном итоге прекратить их поддержку в течение цикла выпусков Kotlin 2.2.20–2.4.0. К ним относятся следующие целевые платформы:

  • macosX64

  • iosX64

  • tvosX64

  • watchosX64

Дополнительные сведения об уровнях поддержки см. в разделе Поддержка целевых платформ Kotlin/Native.

Kotlin/Wasm

Kotlin/Wasm теперь находится на этапе Beta, что обеспечивает большую стабильность и такие улучшения, как разделение зависимостей npm, усовершенствованная обработка исключений при взаимодействии с JavaScript, встроенная поддержка отладки в браузере и другие.

Разделение зависимостей npm

Ранее в проектах Kotlin/Wasm все зависимости npm устанавливались вместе в папке проекта, включая зависимости инструментов Kotlin и ваши собственные. Они также записывались вместе в файлы блокировки проекта (package-lock.json или yarn.lock).

В результате при обновлении зависимостей инструментов Kotlin приходилось обновлять файлы блокировки, даже если вы ничего не добавляли и не изменяли.

Начиная с Kotlin 2.2.20, зависимости npm инструментов Kotlin устанавливаются за пределами проекта. Теперь у инструментов и ваших (пользовательских) зависимостей отдельные каталоги:

  • Каталог зависимостей инструментов:

    <kotlin-user-home>/kotlin-npm-tooling/<yarn|npm>/hash/node_modules

  • Каталог пользовательских зависимостей:

    build/wasm/node_modules

Кроме того, файлы блокировки в каталоге проекта содержат только зависимости, заданные пользователем.

Это улучшение позволяет сосредоточить файлы блокировки только на ваших зависимостях, упрощает структуру проекта и сокращает количество ненужных изменений в файлах.

Это изменение включено по умолчанию для целевой платформы wasm-js. Для целевой платформы js оно пока не реализовано. В будущем планируется добавить эту возможность, однако в Kotlin 2.2.20 зависимости npm для целевой платформы js работают по-прежнему.

Улучшенная обработка исключений при взаимодействии Kotlin/Wasm с JavaScript

Ранее Kotlin было сложно обрабатывать исключения (ошибки), возникающие в JavaScript (JS) и передаваемые в код Kotlin/Wasm.

В некоторых случаях проблема возникала и в обратном направлении: когда исключение выбрасывалось или передавалось через код Wasm в JS, оно оборачивалось в WebAssembly.Exception без каких-либо подробностей. Эти проблемы с обработкой исключений в Kotlin затрудняли отладку.

Начиная с Kotlin 2.2.20, работа с исключениями улучшается в обоих направлениях:

  • Если исключения выбрасываются из JS, на стороне Kotlin доступно больше информации. Если такое исключение проходит через Kotlin обратно в JS, оно больше не оборачивается в WebAssembly.

  • Исключения, выбрасываемые из Kotlin, теперь можно перехватить на стороне JS как ошибки JS.

Новая обработка исключений автоматически работает в современных браузерах, поддерживающих функцию WebAssembly.JSTag:

  • Chrome 115+

  • Firefox 129+

  • Safari 18.4+

В более старых браузерах обработка исключений остается без изменений.

Поддержка отладки в браузерах без настройки

Ранее браузеры не могли автоматически получать исходный код проекта Kotlin/Wasm, необходимый для отладки. Чтобы отлаживать приложения Kotlin/Wasm в браузере, нужно было вручную настроить сборку для предоставления этих исходных файлов, добавив следующий фрагмент в файл build.gradle(.kts):

devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
    static = (static ?: mutableListOf()).apply {
        add(project.rootDir.path)
    }
}

Начиная с Kotlin 2.2.20, отладка приложений в современных браузерах работает сразу после установки. При запуске задач разработки Gradle (*DevRun) Kotlin автоматически предоставляет браузеру исходные файлы. Это позволяет устанавливать точки останова, проверять переменные и пошагово выполнять код Kotlin без дополнительной настройки.

Это изменение упрощает отладку, устраняя необходимость в ручной настройке. Необходимая конфигурация теперь включена в плагин Kotlin Gradle. Если вы ранее добавили эту конфигурацию в файл build.gradle(.kts), удалите ее во избежание конфликтов.

Отладка в браузерах включена по умолчанию для всех задач Gradle *DevRun. Эти задачи предоставляют не только приложение, но и его исходные файлы, поэтому используйте их только для локальной разработки и не запускайте в облачных средах или в рабочей среде, где исходные файлы будут общедоступны.

Как устранить повторную перезагрузку при отладке

Предоставление исходных файлов по умолчанию может привести к повторной перезагрузке приложения в браузере до завершения компиляции Kotlin и сборки пакета. Чтобы устранить эту проблему, измените конфигурацию webpack: укажите игнорировать исходные файлы Kotlin и отключите отслеживание предоставляемых статических файлов. Добавьте файл .js со следующим содержимым в каталог webpack.config.d в корне проекта:

config.watchOptions = config.watchOptions || {
    ignored: ["**/*.kt", "**/node_modules"]
}

if (config.devServer) {
    config.devServer.static = config.devServer.static.map(file => {
        if (typeof file === "string") {
        return { directory: file,
                 watch: false,
        }
    } else {
        return file
    }
    })
}

Устранение пустых файлов yarn.lock

Ранее плагин Kotlin Gradle (KGP) автоматически создавал файл yarn.lock с информацией о пакетах npm, необходимых инструментарию Kotlin, а также о существующих зависимостях npm проекта или используемых библиотек.

Теперь KGP управляет зависимостями инструментария отдельно, а файл yarn.lock на уровне проекта больше не создается, если в проекте нет зависимостей npm.

KGP автоматически создает файл yarn.lock при добавлении зависимостей npm и удаляет файл yarn.lock при их удалении.

Это изменение упрощает структуру проектов и облегчает отслеживание появления реальных зависимостей npm.

Дополнительная настройка не требуется. По умолчанию это поведение применяется в проектах Kotlin/Wasm начиная с Kotlin 2.2.20.

Новая ошибка компилятора для полных имен классов

В Kotlin/Wasm компилятор по умолчанию не сохраняет полные имена классов (FQN) в сгенерированном двоичном файле. Это позволяет избежать увеличения размера приложения.

В результате в предыдущих версиях Kotlin при вызове свойства KClass::qualifiedName возвращалась пустая строка вместо полного имени класса.

Начиная с Kotlin 2.2.20, компилятор сообщает об ошибке при использовании свойства KClass::qualifiedName в проектах Kotlin/Wasm, если только вы явно не включите поддержку полных имен.

Это изменение предотвращает появление неожиданных пустых строк при вызове свойства qualifiedName и улучшает работу разработчиков, выявляя проблемы во время компиляции.

Диагностика включена по умолчанию, и сообщения об ошибках выводятся автоматически. Чтобы отключить диагностику и разрешить сохранение FQN в Kotlin/Wasm, укажите компилятору сохранять полные имена всех классов, добавив следующий параметр в файл build.gradle(.kts):

kotlin {
    wasmJs {
        ...
        compilerOptions {
            freeCompilerArgs.add("-Xwasm-kclass-fqn")
        }
    }
}

Имейте в виду, что включение этого параметра увеличивает размер приложения.

Kotlin/JS

Kotlin 2.2.20 поддерживает использование типа BigInt для представления типа Long в Kotlin, что позволяет использовать Long в экспортируемых объявлениях. Кроме того, в этом выпуске добавлена функция DSL для очистки аргументов Node.js.

Использование типа BigInt для представления типа Long в Kotlin

До стандарта ES2020 JavaScript (JS) не поддерживал примитивный тип для точного представления целых чисел размером более 53 бит.

По этой причине Kotlin/JS представлял значения Long (шириной 64 бита) в виде объектов JavaScript, содержащих два свойства number. Такая пользовательская реализация усложняла взаимодействие Kotlin и JavaScript.

Начиная с Kotlin 2.2.20, при компиляции в современный JavaScript (ES2020) Kotlin/JS использует встроенный тип JavaScript BigInt для представления значений Long в Kotlin.

Это изменение позволяет экспортировать тип Long в JavaScript — возможность, также появившуюся в Kotlin 2.2.20. Благодаря этому взаимодействие Kotlin и JavaScript становится проще.

Чтобы включить эту возможность, добавьте следующий параметр компилятора в файл build.gradle(.kts):

kotlin {
    js {
        ...
        compilerOptions {
            freeCompilerArgs.add("-Xes-long-as-bigint")
        }
    }
}

Эта возможность является экспериментальной. Будем рады вашим отзывам в нашем трекере задач YouTrack.

Использование Long в экспортируемых объявлениях

Из-за того, что Kotlin/JS использовал собственное представление Long, было сложно обеспечить простой способ взаимодействия с типом Long в Kotlin из JavaScript. Поэтому нельзя было экспортировать в JavaScript код Kotlin, использующий тип Long. Эта проблема затрагивала любой код с Long, например параметры функций, свойства классов или конструкторы.

Теперь, когда тип Long в Kotlin можно компилировать в тип BigInt в JavaScript, Kotlin/JS поддерживает экспорт значений Long в JavaScript, упрощая взаимодействие кода Kotlin и JavaScript.

Чтобы включить эту возможность:

  1. Разрешите экспорт Long в Kotlin/JS, добавив следующий параметр компилятора в атрибут freeCompilerArgs файла build.gradle(.kts):

    kotlin {
        js {
            ...
            compilerOptions {                   
                freeCompilerArgs.add("-XXLanguage:+JsAllowLongInExportedDeclarations")
            }
        }
    }
    
  2. Включите тип BigInt. Инструкции см. в разделе «Использование типа BigInt для представления типа Long в Kotlin».

Новая функция DSL для упрощения работы с аргументами

При запуске приложения Kotlin/JS с Node.js передаваемые программе аргументы (args) включали:

  • Путь к исполняемому файлу Node.

  • Путь к скрипту.

  • Фактически переданные аргументы командной строки.

Однако ожидалось, что args будет содержать только аргументы командной строки. Для этого приходилось вручную пропускать первые два аргумента с помощью функции drop() в файле build.gradle(.kts) или в коде Kotlin:

fun main(args: Array<String>) {
    println(args.drop(2).joinToString(", "))
}

Это решение приходилось постоянно повторять, оно могло приводить к ошибкам и плохо подходило для совместного использования кода на разных платформах.

Чтобы решить эту проблему, в Kotlin 2.2.20 добавлена новая функция DSL под названием passCliArgumentsToMainFunction().

С этой функцией учитываются только аргументы командной строки, а пути к Node и скрипту исключаются:

fun main(args: Array<String>) {
    // No need for drop() and only your custom arguments are included 
    println(args.joinToString(", "))
}

Это изменение сокращает объем шаблонного кода, предотвращает ошибки при ручном удалении аргументов и улучшает кроссплатформенную совместимость.

Чтобы включить эту возможность, добавьте следующую функцию DSL в файл build.gradle(.kts):

kotlin {
    js {
        nodejs {
            passCliArgumentsToMainFunction()
        }
    }
}

Gradle

В Kotlin 2.2.20 добавлены новые метрики производительности компилятора для задач Kotlin/Native в отчетах о сборке Gradle, а также улучшения инкрементальной компиляции.

Новые метрики производительности компилятора в отчетах о сборке для задач Kotlin/Native

В Kotlin 1.7.0 мы представили отчеты о сборке, помогающие отслеживать производительность компилятора. С тех пор мы добавили в эти отчеты дополнительные метрики, чтобы сделать их еще подробнее и полезнее при анализе проблем с производительностью.

В Kotlin 2.2.20 отчеты о сборке теперь включают метрики производительности компилятора для задач Kotlin/Native.

Дополнительную информацию об отчетах о сборке и их настройке см. в разделе Включение отчетов о сборке.

Предварительная версия улучшенной инкрементальной компиляции для Kotlin/JVM

В Kotlin 2.0.0 появился новый компилятор K2 с оптимизированным внешним интерфейсом. В Kotlin 2.2.20 это решение развивается: новый внешний интерфейс используется для повышения производительности в некоторых сложных сценариях инкрементальной компиляции Kotlin/JVM.

Пока мы работаем над стабилизацией поведения, эти улучшения по умолчанию отключены. Чтобы включить их, добавьте следующее свойство в файл gradle.properties:

kotlin.incremental.jvm.fir=true

Сейчас плагин компилятора kapt несовместим с этим новым поведением. Мы работаем над добавлением поддержки в одном из будущих выпусков Kotlin.

Будем рады вашим отзывам об этой возможности в YouTrack.

Инкрементальная компиляция обнаруживает изменения в лямбдах встроенных функций

До Kotlin 2.2.20, если вы включали инкрементальную компиляцию и изменяли логику внутри лямбды встроенной функции, компилятор не перекомпилировал места вызова этой функции в других модулях. В результате в этих местах вызова использовалась предыдущая версия лямбды, что могло приводить к неожиданному поведению.

В Kotlin 2.2.20 компилятор теперь обнаруживает изменения в лямбдах встроенных функций и автоматически перекомпилирует места их вызова.

Улучшения публикации библиотек

В Kotlin 2.2.20 добавлены новые задачи Gradle, упрощающие публикацию библиотек. С их помощью можно создавать пары ключей, загружать открытые ключи и выполнять локальные проверки, чтобы убедиться в успешном прохождении проверки до загрузки в репозиторий Maven Central.

Дополнительную информацию об использовании этих задач в процессе публикации см. в разделе Публикация библиотеки в Maven Central.

Новые задачи Gradle для создания и загрузки ключей PGP

До Kotlin 2.2.20 для публикации мультиплатформенной библиотеки в репозитории Maven Central требовалось установить стороннюю программу, например gpg, чтобы создать пару ключей для подписания публикаций. Теперь в плагин Kotlin Gradle включены задачи Gradle, позволяющие создавать пару ключей и загружать открытый ключ без установки дополнительной программы.

Создание пары ключей

Задача generatePgpKeys создает пару ключей. При ее запуске необходимо указать пароль для хранилища закрытого ключа и свое имя в следующем формате:

./gradlew -Psigning.password=example-password generatePgpKeys --name "John Smith <john@example.com>"

Задача сохраняет пару ключей в каталоге build/pgp.

Переместите пару ключей в безопасное место, чтобы предотвратить случайное удаление или несанкционированный доступ.

Загрузка открытого ключа

Задача uploadPublicPgpKey загружает открытый ключ на сервер ключей Ubuntu: keyserver.ubuntu.com. При ее запуске укажите путь к открытому ключу в формате .asc:

./gradlew uploadPublicPgpKey --keyring /path_to/build/pgp/public_KEY_ID.asc

Новые задачи Gradle для локальной проверки верификации

В Kotlin 2.2.20 также добавлены задачи Gradle для локальной проверки верификации перед загрузкой библиотеки в репозиторий Maven Central.

Если вы используете плагин Kotlin Gradle вместе с плагином Signing и плагином Maven Publish для Gradle, можно запустить задачи checkSigningConfiguration и checkPomFileFor<PUBLICATION_NAME>Publication, чтобы проверить соответствие вашей конфигурации требованиям Maven Central. Замените <PUBLICATION_NAME> именем публикации.

Эти задачи не запускаются автоматически в составе задач Gradle build или check, поэтому их нужно запускать вручную. Например, если у вас есть публикация KotlinMultiplatform:

./gradlew checkSigningConfiguration checkPomFileForKotlinMultiplatformPublication

Задача checkSigningConfiguration проверяет, что:

  • Для плагина Signing настроены ключи.

  • Настроенный открытый ключ загружен на один из серверов ключей: keyserver.ubuntu.com или keys.openpgp.org.

  • Для всех публикаций включено подписание.

Если какая-либо из этих проверок не пройдена, задача сообщает об ошибке и указывает, как ее исправить.

Задача checkPomFileFor<PUBLICATION_NAME>Publication проверяет соответствие файла pom.xml требованиям Maven Central. Если файл им не соответствует, задача сообщает об ошибке и указывает, какие части файла pom.xml не соответствуют требованиям.

Maven: поддержка демона Kotlin в kotlin-maven-plugin

В Kotlin 2.2.20 возможности API средств сборки, представленного в Kotlin 2.2.0, расширены за счет поддержки демона Kotlin в kotlin-maven-plugin. При использовании демона Kotlin компилятор Kotlin работает в отдельном изолированном процессе, что не позволяет другим плагинам Maven переопределять системные свойства. Пример приведен в этой задаче YouTrack.

Начиная с Kotlin 2.2.20, по умолчанию используется демон Kotlin. Чтобы вернуться к предыдущему поведению, отключите его, установив для следующего свойства в файле pom.xml значение false:

<properties>
    <kotlin.compiler.daemon>false</kotlin.compiler.daemon>
</properties>

В Kotlin 2.2.20 также добавлено новое свойство jvmArgs, которое позволяет настроить аргументы JVM по умолчанию для демона Kotlin. Например, чтобы переопределить параметры -Xmx и -Xms, добавьте в файл pom.xml следующее:

<properties>
    <kotlin.compiler.daemon.jvmArgs>Xmx1500m,Xms500m</kotlin.compiler.daemon.jvmArgs>
</properties>

Новая общая схема параметров компилятора Kotlin

В Kotlin 2.2.20 представлена общая схема для всех параметров компилятора, опубликованная в артефакте org.jetbrains.kotlin:kotlin-compiler-arguments-description. Этот артефакт содержит программное представление и эквивалент в формате JSON (для потребителей, не использующих JVM) всех параметров компилятора, их описания и метаданные, например версию, в которой каждый параметр был добавлен или переведен в стабильный статус. Эту схему можно использовать для создания собственного представления параметров или их анализа.

Стандартная библиотека

В этом выпуске представлены новые экспериментальные возможности стандартной библиотеки: поддержка рефлексии для определения типов интерфейсов в Kotlin/JS, функции обновления для общих атомарных типов и перегрузки copyOf() для изменения размера массивов.

Поддержка определения типов интерфейсов с помощью рефлексии в Kotlin/JS

В Kotlin 2.2.20 в стандартную библиотеку Kotlin/JS добавлено экспериментальное свойство KClass.isInterface.

С помощью этого свойства можно проверить, является ли ссылка на класс интерфейсом Kotlin. Это приближает Kotlin/JS к Kotlin/JVM, где для проверки того, представляет ли класс интерфейс, можно использовать KClass.java.isInterface.

Чтобы включить эту возможность, используйте аннотацию @OptIn(ExperimentalStdlibApi::class):

@OptIn(ExperimentalStdlibApi::class)
fun inspect(klass: KClass<*>) {
    // Prints true for interfaces
    println(klass.isInterface)
}

Будем рады вашим отзывам в нашем трекере задач YouTrack.

Новые функции обновления для общих атомарных типов

В Kotlin 2.2.20 добавлены новые экспериментальные функции для обновления общих атомарных типов и элементов соответствующих массивов. Каждая функция атомарно вычисляет новое значение с помощью одной из этих функций обновления и заменяет текущее значение. Возвращаемое значение зависит от выбранной функции:

  • update() и updateAt() устанавливают новое значение, не возвращая результат.

  • fetchAndUpdate() и fetchAndUpdateAt() устанавливают новое значение и возвращают значение, которое было до изменения.

  • updateAndFetch() и updateAndFetchAt() устанавливают новое значение и возвращают обновленное значение.

Эти функции можно использовать для реализации атомарных преобразований, которые не поддерживаются из коробки, например умножения или побитовых операций. До этого изменения для увеличения общего атомарного значения и чтения предыдущего значения требовался цикл с функцией compareAndSet().

Как и все API для общих атомарных типов, эти функции являются экспериментальными. Чтобы включить их, используйте аннотацию @OptIn(ExperimentalAtomicApi::class).

Ниже приведен пример кода, выполняющего разные виды обновлений и возвращающего предыдущее или обновленное значение:

import kotlin.concurrent.atomics.*
import kotlin.random.Random

@OptIn(ExperimentalAtomicApi::class)
fun main() {
    val counter = AtomicLong(Random.nextLong())
    val minSetBitsThreshold = 20

    // Sets a new value without using the result
    counter.update { if (it < 0xDECAF) 0xCACA0 else 0xC0FFEE }

    // Retrieves the current value, then updates it
    val previousValue = counter.fetchAndUpdate { 0x1CEDL.shl(Long.SIZE_BITS - it.countLeadingZeroBits()) or it }

    // Updates the value, then retrieves the result
    val current = counter.updateAndFetch {
        if (it.countOneBits() < minSetBitsThreshold) it.shl(20) or 0x15BADL else it
    }

    val hexFormat = HexFormat {
        upperCase = true
        number {
            removeLeadingZeros = true
        }
    }
    println("Previous value: ${previousValue.toHexString(hexFormat)}")
    println("Current value: ${current.toHexString(hexFormat)}")
    println("Expected status flag set: ${current and 0xBAD != 0xBADL}")
}

Будем рады вашим отзывам в нашем трекере задач YouTrack.

Поддержка перегрузок copyOf() для массивов

В Kotlin 2.2.20 добавлена экспериментальная перегрузка функции copyOf(). Она доступна для массивов обобщенного типа Array<T> и всех типов массивов примитивов.

Эту функцию можно использовать, чтобы увеличить размер массива и заполнить новые элементы значениями из лямбды-инициализатора. Это позволяет сократить объем пользовательского шаблонного кода и решить распространенную проблему: изменение размера обобщенного Array<T> приводило к nullable-результату (Array<T?>).

Пример:

@OptIn(ExperimentalStdlibApi::class)
fun main() {
    val row1: Array<String> = arrayOf("one", "two")
    // Resizes the array and populates the new elements using the lambda
    val row2: Array<String> = row1.copyOf(4) { "default" }
    println(row2.contentToString())
    // [one, two, default, default]
}

Этот API является экспериментальным. Чтобы включить его, используйте аннотацию @OptIn(ExperimentalStdlibApi::class).

Будем рады вашим отзывам в нашем трекере задач.

Компилятор Compose

В этом выпуске компилятор Compose повышает удобство работы: добавлены новые предупреждения, а вывод метрик сборки улучшен и стал более понятным.

Ограничения версии языка для параметров по умолчанию

В этом выпуске компилятор Compose сообщает об ошибке, если указанная для компиляции версия языка ниже минимальной версии, необходимой для поддержки параметров по умолчанию в абстрактных или открытых компонуемых функциях.

Компилятор Compose поддерживает параметры по умолчанию: для абстрактных функций — начиная с Kotlin 2.1.0, а для открытых функций — начиная с Kotlin 2.2.0. При использовании более новой версии компилятора Compose с более старыми версиями языка Kotlin разработчикам библиотек следует учитывать, что параметры по умолчанию в абстрактных или открытых функциях могут по-прежнему отображаться в публичном API, даже если версия языка их не поддерживает.

Предупреждения о целях Composable для компилятора K2

В этом выпуске добавлены предупреждения о несоответствиях @ComposableTarget при использовании компилятора K2.

Например:

@Composable fun App() {
  Box { // <-- `Box` is a `@UiComposable`
    Path(...) // <-- `Path` is a `@VectorComposable`
    ^^^^^^^^^
    warning: Calling a Vector composable function where a UI composable was expected
  }
}

Полные имена в метриках сборки

Имена классов и функций, указанные в метриках сборки, теперь приводятся полностью, что упрощает различение объявлений с одинаковыми именами в разных пакетах.

Кроме того, метрики сборки больше не содержат дамп сложных выражений из параметров по умолчанию, поэтому их стало проще читать.

Несовместимые изменения и устаревшие возможности

В этом разделе перечислены важные несовместимые изменения и устаревшие возможности, на которые стоит обратить внимание:

  • Плагин компилятора kapt теперь по умолчанию использует компилятор K2. В результате свойство kapt.use.k2, которое определяет, использует ли плагин компилятор K2, объявлено устаревшим. Если задать этому свойству значение false, чтобы отказаться от использования компилятора K2, Gradle выведет предупреждение.

Обновления документации

В документации Kotlin появились важные изменения:

  • План развития Kotlin — ознакомьтесь с обновлённым списком приоритетов развития языка и экосистемы Kotlin.

  • Свойства — узнайте о различных способах использования свойств в Kotlin.

  • Условия и циклы — узнайте, как работают условия и циклы в Kotlin.

  • Kotlin/JavaScript — изучите сценарии использования Kotlin/JS.

  • Разработка для веба — узнайте о различных целевых платформах, которые Gradle предлагает для веб-разработки.

  • Демон Kotlin — узнайте о демоне Kotlin и о том, как он взаимодействует с системами сборки и компилятором Kotlin.

  • Обзор корутин — познакомьтесь с основными понятиями, связанными с корутинами, и начните их изучать.

  • Параметры бинарных файлов Kotlin/Native — узнайте о параметрах бинарных файлов Kotlin/Native и о том, как их настроить.

  • Отладка Kotlin/Native — изучите различные способы отладки с помощью Kotlin/Native.

  • Советы по настройке серверной части LLVM — узнайте, как Kotlin/Native использует LLVM, и настройте проходы оптимизации.

  • Начало работы с DAO API Exposed — узнайте, как использовать API объекта доступа к данным (DAO) в Exposed для хранения и извлечения данных из реляционной базы данных.

  • Новые страницы документации Exposed, посвящённые R2DBC:

    • Работа с базами данных

    • Работа с ConnectionFactory

    • Сопоставление пользовательских типов

  • Интеграция с HTMX — узнайте, как Ktor обеспечивает экспериментальную первоклассную поддержку HTMX.

Как обновиться до Kotlin 2.2.20

Плагин Kotlin распространяется как встроенный плагин для IntelliJ IDEA и Android Studio.

Чтобы перейти на новую версию Kotlin, измените версию Kotlin на 2.2.20 в сценариях сборки.

15 января 2026 г.
Руководство по совместимости с Kotlin 2.3.xЧто нового в Kotlin 2.2.0

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/whatsnew2220.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API