Что нового в Kotlin 2.3.20
Вышел Kotlin 2.3.20! Вот основные изменения:
Gradle: Совместимость с Gradle 9.3.0 и Компиляция Kotlin/JVM по умолчанию использует BTA
Плагины компилятора Kotlin: Lombok получил статус «Альфа» и улучшена поддержка JPA в плагине
kotlin.plugin.jpaСтандартная библиотека: Новый API для создания неизменяемых копий
Map.EntryKotlin/Native: Новый режим взаимодействия с библиотеками C и Objective-C
Обновление до Kotlin 2.3.20
Последняя версия Kotlin входит в последние версии IntelliJ IDEA и Android Studio.
Чтобы обновить Kotlin до новой версии, убедитесь, что ваша IDE обновлена до последней версии, и измените версию Kotlin на 2.3.20 в сценариях сборки.
Новые возможности
В этом выпуске следующая возможность имеет статус «Стабильная»:
Упрощенная настройка проектов Kotlin
В Kotlin 2.3.20 настроить Kotlin в проектах Maven стало проще. Теперь Kotlin поддерживает автоматическую настройку корневых каталогов исходного кода и стандартной библиотеки Kotlin.
Благодаря новой настройке при создании проекта Kotlin с системой сборки Maven или добавлении Kotlin в существующий проект Java Maven вам не нужно вручную указывать пути к корневым каталогам исходного кода или добавлять зависимость kotlin-stdlib в файл сборки POM.
Как включить
В файле pom.xml добавьте <extensions>true</extensions> в раздел <build><plugins> плагина Kotlin Maven:
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>2.4.20</version>
<extensions>true</extensions> <!-- Add this extension -->
</plugin>
</plugins>
</build>
Новые возможности параметра <extensions>:
Регистрация каталогов
src/main/kotlinиsrc/test/kotlinв качестве корневых каталогов исходного кода, если они существуют, но не указаны в конфигурации плагина.Добавление зависимости
kotlin-stdlib, если она еще не указана явно.
Также можно отключить автоматическое добавление стандартной библиотеки Kotlin. Для этого добавьте следующий код в раздел <properties>:
<project>
<properties>
<!-- Disable smart defaults via property -->
<kotlin.smart.defaults.enabled>false</kotlin.smart.defaults.enabled>
</properties>
</project>
Обратите внимание, что это свойство отключает не только автоматическое добавление стандартной библиотеки, но и регистрацию путей к корневым каталогам исходного кода. Другие возможности <extensions> не затрагиваются.
Дополнительные сведения о настройке проектов Kotlin Maven см. в разделе Настройка проекта Maven.
Новые возможности
В этом выпуске доступны следующие возможности, не достигшие стабильного статуса. К ним относятся возможности со статусами «Бета», «Альфа» и «Экспериментальная»:
Стандартная библиотека: новый API для создания неизменяемых копий
Map.EntryKotlin/Native: новый режим взаимодействия с библиотеками C и Objective-C
Lombok получил статус «Альфа»
В Kotlin 1.5.20 появился экспериментальный плагин компилятора Lombok, который позволяет создавать и использовать объявления Lombok в Java в модулях, сочетающих код Kotlin и Java.
В версии 2.3.20 плагин компилятора Lombok получил статус «Альфа», поскольку мы планируем подготовить эту функциональность к использованию в производственной среде, однако она все еще находится в разработке.
Деструктуризация на основе имен
В Kotlin 2.3.20 появились деструктурирующие объявления на основе имен, в которых переменные сопоставляются с именами свойств, а не с порядком функций componentN().
Ранее в деструктурирующих объявлениях использовалась позиционная деструктуризация:
data class User(val username: String, val email: String)
fun main() {
val user = User("alice", "alice@example.com")
val (email, username) = user
println(email)
// alice
println(username)
// alice@example.com
}
В этом примере, поскольку деструктуризация зависит от порядка функций componentN(), email получает значение username, а username — значение email.
Начиная с Kotlin 2.3.20 можно использовать деструктуризацию на основе имен, при которой каждая переменная ссылается на свойство по имени:
fun main() {
val user = User("alice", "alice@example.com")
// Uses name-based destructuring with explicit form
(val mail = email, val name = username) = user
println(name)
// alice
println(mail)
// alice@example.com
}
Деструктуризация на основе имен имеет статус «Экспериментальная». Управлять интерпретацией деструктурирующих объявлений компилятором можно с помощью параметра компилятора -Xname-based-destructuring.
Доступны следующие режимы:
only-syntaxвключает явную форму деструктуризации на основе имен, не меняя поведение существующих деструктурирующих объявлений.name-mismatchвыводит предупреждения, если при позиционной деструктуризации в классах данных используются имена переменных, не совпадающие с именами свойств.completeвключает сокращенную форму деструктуризации на основе имен с круглыми скобками и сохраняет поддержку позиционной деструктуризации с квадратными скобками.
В режиме complete сокращенный синтаксис деструктуризации с круглыми скобками сопоставляет переменные с именами свойств, а не с их позициями:
val (email, username) = user
Как включить
Чтобы использовать деструктуризацию на основе имен в проекте, добавьте параметр компилятора в файл конфигурации сборки:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
}
}
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xname-based-destructuring=only-syntax</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>
Включение деструктуризации на основе имен также добавляет новый синтаксис позиционной деструктуризации с квадратными скобками:
// Uses explicit position-based destructuring val [username, email] = user
Мы планируем постепенно перейти к деструктурирующим объявлениям, использующим по умолчанию сопоставление по именам, сохранив позиционную деструктуризацию с новым синтаксисом квадратных скобок.
Дополнительные сведения см. в KEEP этой возможности.
Будем признательны за ваши отзывы в YouTrack.
Новый API для создания неизменяемых копий Map.Entry
В Kotlin 2.3.20 появилась функция расширения Map.Entry.copy() для создания неизменяемой копии Map.Entry. Эта функция позволяет повторно использовать записи, полученные из Map.entries, после изменения карты, предварительно скопировав их.
Map.Entry.copy() имеет статус «Экспериментальная». Чтобы включить эту возможность, используйте аннотацию @OptIn(ExperimentalStdlibApi::class) или параметр компилятора:
-opt-in=kotlin.ExperimentalStdlibApi
Вот пример использования Map.Entry.copy() для удаления записей из изменяемой карты:
@OptIn(ExperimentalStdlibApi::class)
fun main() {
val map = mutableMapOf(1 to 1, 2 to 2, 3 to 3, 4 to 4)
val toRemove = map.entries
.filter { it.key % 2 == 0 }
.map { it.copy() }
map.entries.removeAll(toRemove)
println("map = $map")
// map = {1=1, 3=3}
}
Новый режим взаимодействия с библиотеками C и Objective-C
Если вы используете библиотеки C или Objective-C в библиотеках или приложениях Kotlin Multiplatform (KMP), предлагаем протестировать новый режим взаимодействия и поделиться результатами.
В целом Kotlin/Native позволяет импортировать библиотеки C и Objective-C в Kotlin. Однако в библиотеках KMP на эту возможность в настоящее время влияют проблемы совместимости KMP со старыми версиями компилятора.
Иными словами, если вы публикуете библиотеку KMP, скомпилированную одной версией Kotlin, импорт библиотек C или Objective-C может сделать невозможным использование этой библиотеки Kotlin в проектах с более ранней версией Kotlin.
Чтобы решить эту и другие проблемы, команда Kotlin пересматривает используемый внутри механизм взаимодействия. Начиная с Kotlin 2.3.20 новый режим можно опробовать с помощью параметра компилятора.
Как включить
В файле сборки Gradle проверьте, есть ли у вас блок
cinterops {}или зависимостьpod(). Если они присутствуют, ваш проект использует библиотеки C или Objective-C.Убедитесь, что проект использует
2.3.20или более позднюю версию.-
В том же файле сборки добавьте параметр компилятора
-Xccall-modeпри вызове инструмента cinterop:kotlin { targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>().configureEach { compilations.configureEach { cinterops.configureEach { extraOpts += listOf("-Xccall-mode", "direct") } } } } Соберите и протестируйте проект как обычно: запустите модульные тесты, приложение и т. д. Также можно использовать параметр
--continue, чтобы разрешить Gradle продолжать выполнение задач даже после сбоев и тем самым обнаружить больше проблем за один раз.
Поделитесь результатами
В большинстве случаев новый режим взаимодействия должен стать полноценной заменой текущему. В дальнейшем мы планируем включить его по умолчанию. Чтобы этого добиться, нужно убедиться, что он работает как можно лучше, и протестировать его на широком круге проектов, поскольку:
В новом режиме пока поддерживаются не все объявления C и Objective-C (в основном из-за проблем совместимости). Мы хотели бы лучше понять влияние этого ограничения на реальные проекты и соответствующим образом расставить приоритеты для дальнейшей работы.
Возможны ошибки или упущенные нами нюансы. Тестирование языков со множеством взаимодействующих возможностей — непростая задача, а тестирование взаимодействия между языками, каждый из которых имеет уникальный набор возможностей, еще сложнее.
Помогите нам изучить реальные проекты и выявить сложные случаи. Независимо от того, столкнулись ли вы с проблемами, поделитесь результатами в комментариях на YouTrack.
Язык
В Kotlin 2.3.20 появились деструктурирующие объявления на основе имен, в которых переменные сопоставляются с именами свойств, а не с их позициями. Также изменено разрешение перегрузок для объявлений с контекстными параметрами.
Изменения в разрешении перегрузок для контекстных параметров
В Kotlin 2.3.20 изменено разрешение перегрузок для объявлений с контекстными параметрами.
Ранее при разрешении перегрузок объявления с контекстными параметрами считались более конкретными, чем объявления без них.
Начиная с Kotlin 2.3.20 это правило больше не применяется, благодаря чему выбор перегрузки стал более единообразным. В результате вызовы, которые раньше успешно разрешались, теперь становятся неоднозначными и приводят к ошибке компиляции, если перегрузки различаются только контекстными параметрами. В таких случаях компилятор предупреждает о возможной неоднозначности.
Пример:
class Logger {
fun info(msg: String) = println("INFO: $msg")
}
fun saveUser(id: Int) {
println("Saving user $id (no logger)")
}
// Reports a warning: Contextual declaration is shadowed
context(logger: Logger)
fun saveUser(id: Int) {
logger.info("Saving user $id")
}
fun main() {
val logger = Logger()
context(logger) {
// Reports an ambiguity error in 2.3.20
saveUser(1)
}
}
Кроме того, в Kotlin 2.3.20 количество перегрузок kotlin.context сокращено с 22 до 6, чтобы уменьшить число избыточных кандидатов при разрешении перегрузок и автодополнении кода.
Деструктуризация на основе имен
В Kotlin 2.3.20 появились деструктурирующие объявления на основе имен, в которых переменные сопоставляются с именами свойств, а не с порядком функций componentN().
Ранее в деструктурирующих объявлениях использовалась позиционная деструктуризация:
data class User(val username: String, val email: String)
fun main() {
val user = User("alice", "alice@example.com")
val (email, username) = user
println(email)
// alice
println(username)
// alice@example.com
}
В этом примере, поскольку деструктуризация зависит от порядка функций componentN(), email получает значение username, а username — значение email.
Начиная с Kotlin 2.3.20 можно использовать деструктуризацию на основе имен, при которой каждая переменная ссылается на свойство по имени:
fun main() {
val user = User("alice", "alice@example.com")
// Uses name-based destructuring with explicit form
(val mail = email, val name = username) = user
println(name)
// alice
println(mail)
// alice@example.com
}
Деструктуризация на основе имен имеет статус «Экспериментальная». Управлять интерпретацией деструктурирующих объявлений компилятором можно с помощью параметра компилятора -Xname-based-destructuring.
Доступны следующие режимы:
only-syntaxвключает явную форму деструктуризации на основе имен, не меняя поведение существующих деструктурирующих объявлений.name-mismatchвыводит предупреждения, если при позиционной деструктуризации в классах данных используются имена переменных, не совпадающие с именами свойств.completeвключает сокращенную форму деструктуризации на основе имен с круглыми скобками и сохраняет поддержку позиционной деструктуризации с квадратными скобками.
В режиме complete сокращенный синтаксис деструктуризации с круглыми скобками сопоставляет переменные с именами свойств, а не с их позициями:
val (email, username) = user
Как включить
Чтобы использовать деструктуризацию на основе имен в проекте, добавьте параметр компилятора в файл конфигурации сборки:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
}
}
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xname-based-destructuring=only-syntax</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>
Включение деструктуризации на основе имен также добавляет новый синтаксис позиционной деструктуризации с квадратными скобками:
// Uses explicit position-based destructuring val [username, email] = user
Мы планируем постепенно перейти к деструктурирующим объявлениям, использующим по умолчанию сопоставление по именам, сохранив позиционную деструктуризацию с новым синтаксисом квадратных скобок.
Дополнительные сведения см. в KEEP этой возможности.
Будем признательны за ваши отзывы в YouTrack.
Стандартная библиотека
В Kotlin 2.3.20 появилась новая экспериментальная возможность стандартной библиотеки.
Новый API для создания неизменяемых копий Map.Entry
В Kotlin 2.3.20 появилась функция расширения Map.Entry.copy() для создания неизменяемой копии Map.Entry. Эта функция позволяет повторно использовать записи, полученные из Map.entries, после изменения карты, предварительно скопировав их.
Map.Entry.copy() имеет статус «Экспериментальная». Чтобы включить эту возможность, используйте аннотацию @OptIn(ExperimentalStdlibApi::class) или параметр компилятора:
-opt-in=kotlin.ExperimentalStdlibApi
Вот пример использования Map.Entry.copy() для удаления записей из изменяемой карты:
@OptIn(ExperimentalStdlibApi::class)
fun main() {
val map = mutableMapOf(1 to 1, 2 to 2, 3 to 3, 4 to 4)
val toRemove = map.entries
.filter { it.key % 2 == 0 }
.map { it.copy() }
map.entries.removeAll(toRemove)
println("map = $map")
// map = {1=1, 3=3}
}
Плагины компилятора Kotlin
В Kotlin 2.3.20 появились важные обновления плагинов компилятора Lombok и kotlin.plugin.jpa.
Улучшена поддержка JPA в плагине kotlin.plugin.jpa
Теперь плагин kotlin.plugin.jpa автоматически применяет плагин компилятора all-open с новым встроенным пресетом JPA, а также существующий плагин компилятора no-arg.
Ранее использование kotlin("plugin.jpa") включало только плагин no-arg с пресетами JPA.
В этом выпуске мы улучшили пресет kotlin.plugin.jpa, чтобы плагин all-open настраивался автоматически. Это обеспечивает ожидаемую работу ленивых ассоциаций: они не вызывают жадную загрузку и дополнительные запросы.
Начиная с Kotlin 2.3.20:
Плагин компилятора
all-openпредоставляет пресет JPA.Плагин Gradle
org.jetbrains.kotlin.plugin.jpaавтоматически применяет плагинorg.jetbrains.kotlin.plugin.all-openс включенным пресетом JPA.Настройка JPA в Maven по умолчанию включает
all-openс пресетом JPA. (Поддержка в IntelliJ IDEA доступна начиная с версии 2026.1.)Зависимость Maven
org.jetbrains.kotlin:kotlin-maven-noargтеперь неявно включаетorg.jetbrains.kotlin:kotlin-maven-allopen, поэтому больше не нужно добавлять ее явно в блок<plugin><dependencies>.
В результате сущности JPA с приведенными ниже аннотациями автоматически обрабатываются как open и получают конструкторы без аргументов без дополнительной настройки:
javax.persistence.Entityjavax.persistence.Embeddablejavax.persistence.MappedSuperclassjakarta.persistence.Entityjakarta.persistence.Embeddablejakarta.persistence.MappedSuperclass
Это изменение упрощает настройку сборки и улучшает работу Kotlin с платформами JPA сразу после установки.
Lombok получил статус «Альфа»
В Kotlin 1.5.20 появился экспериментальный плагин компилятора Lombok, который позволяет создавать и использовать объявления Lombok в Java в модулях, сочетающих код Kotlin и Java.
В версии 2.3.20 плагин компилятора Lombok получил статус «Альфа», поскольку мы планируем подготовить эту функциональность к использованию в производственной среде, однако она все еще находится в разработке.
Kotlin/JVM
В Kotlin 2.3.20 появилось несколько улучшений взаимодействия с Java. Теперь компилятор распознает аннотацию Vert.x @Nullable для проверки nullability. В этом выпуске также добавлена поддержка аннотаций Java @Unmodifiable и @UnmodifiableView, позволяющая считать аннотированные коллекции доступными только для чтения в Kotlin.
Поддержка аннотации Vert.x @Nullable
В Kotlin 2.3.20 добавлена поддержка аннотации io.vertx.codegen.annotations.Nullable. Теперь компилятор распознает эту аннотацию и по умолчанию сообщает о несоответствиях nullability в виде предупреждений.
Чтобы включить строгие проверки nullability и повысить уровень этих предупреждений до ошибок, добавьте в файл сборки следующий параметр компилятора:
// build.gradle(.kts)
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xnullability-annotations=@io.vertx.codegen.annotations:strict")
}
}
<!-- pom.xml -->
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xnullability-annotations=@io.vertx.codegen.annotations:strict</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>
Поддержка аннотаций Java для неизменяемых коллекций
В Kotlin 2.3.20 добавлена поддержка аннотаций Java org.jetbrains.annotations.Unmodifiable и org.jetbrains.annotations.UnmodifiableView.
Начиная с Kotlin 2.3.20 коллекции, возвращаемые из объявлений Java с этими аннотациями, считаются доступными только для чтения в Kotlin. При присваивании такой коллекции переменной изменяемого типа коллекции выводится предупреждение о несоответствии типов. В Kotlin 2.5.0 это предупреждение планируется преобразовать в ошибку.
Пример:
// Java
public class Java {
public static @UnmodifiableView List<Object> unmodifiableView() {
return List.of();
}
public static @Unmodifiable List<Object> unmodifiable() {
return List.of();
}
}
// Kotlin
fun main() {
// Reports a warning: Java type mismatch
val mutableView: MutableList<Any> = Java.unmodifiableView()
val mutableCopy: MutableList<Any> = Java.unmodifiable()
}
Kotlin/Native
В Kotlin 2.3.20 появился новый экспериментальный режим взаимодействия с библиотеками C и Objective-C, средство проверки кросс-компиляции и новый DSL для отключения кэша компиляции в проектах Kotlin/Native.
Средство проверки кросс-компиляции
В Kotlin 2.3.20 появился способ определить, поддерживается ли кросс-компиляция для указанной цели. Это может быть полезно для сторонних плагинов, отслеживающих состояние задач компиляции.
Как правило, Kotlin/Native поддерживает кросс-компиляцию: любой поддерживаемый хост может создавать артефакты .klib для поддерживаемых целевых платформ. Однако создание артефактов для целевых платформ Apple по-прежнему ограничено, если в проекте используются зависимости cinterop.
Новый API crossCompilationSupported теперь проверяет, поддерживается ли кросс-компиляция: целевая платформа должна быть включена диспетчером хостов, и ни одна из компиляций для этой целевой платформы не должна включать зависимости cinterop. Проверка включена по умолчанию.
Подробнее о поддерживаемых целевых платформах и хостах см. в документации Kotlin/Native.
Новый DSL для отключения кэша компиляции
В Kotlin 2.3.20 появился новый DSL для отключения кэша компиляции в проектах Kotlin/Native. Он призван сделать решение об отключении кэша более обдуманным и явным.
Поскольку отключение кэша значительно замедляет сборку Kotlin/Native, использовать его следует только временно и в исключительных случаях. Поэтому теперь отключение кэша привязано к конкретной версии Kotlin и должно сопровождаться причиной, которая служит документацией.
Если вам необходимо отключить кэш компиляции в проекте, обновите блок binaries {} в файле сборки Gradle следующим образом:
kotlin {
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
// Specify your binary kind
it.binaries.framework {
baseName = "CacheKind"
isStatic = true
// Disable cache with the new DSL
disableNativeCache(
version = DisableCacheInKotlinVersion.2_3_0,
reason = "Cache bug",
issue = URI("https://youtrack.com/YY-1111")
)
}
}
}
version— версия Kotlin, для которой отключен кэш компиляции.reason(обязательно) — причина отключения кэша компиляции.issue(необязательно) — URL соответствующей задачи в системе отслеживания ошибок.
Новый DSL заменяет устаревшее свойство Gradle kotlin.native.cacheKind. Его можно безопасно удалить из файла gradle.properties.
Другие советы по сокращению времени компиляции см. в документации Kotlin/Native.
Новый режим взаимодействия с библиотеками C и Objective-C
Если вы используете библиотеки C или Objective-C в библиотеках или приложениях Kotlin Multiplatform (KMP), предлагаем вам протестировать новый режим взаимодействия и поделиться результатами.
В целом Kotlin/Native позволяет импортировать библиотеки C и Objective-C в Kotlin. Однако в библиотеках KMP на эту возможность сейчас влияют проблемы совместимости KMP со старыми версиями компилятора.
Другими словами, если опубликовать библиотеку KMP, скомпилированную одной версией Kotlin, импорт библиотек C или Objective-C может сделать невозможным использование этой библиотеки Kotlin в проектах с более ранней версией Kotlin.
Чтобы решить эту и другие проблемы, команда Kotlin пересматривает механизм взаимодействия, используемый внутри системы. Начиная с Kotlin 2.3.20, можно попробовать новый режим с помощью параметра компилятора.
Как включить
Проверьте, есть ли в файле сборки Gradle блок
cinterops {}или зависимостьpod(). Если они есть, в проекте используются библиотеки C или Objective-C.Убедитесь, что в проекте используется
2.3.20или более поздняя версия.-
Добавьте параметр компилятора
-Xccall-modeв вызов инструмента cinterop в том же файле сборки:kotlin { targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>().configureEach { compilations.configureEach { cinterops.configureEach { extraOpts += listOf("-Xccall-mode", "direct") } } } } Соберите и протестируйте проект как обычно: запустите модульные тесты, приложение и т. д. Также можно использовать параметр
--continue, чтобы Gradle продолжал выполнять задачи даже после ошибок и помочь обнаружить больше проблем за один раз.
Поделитесь результатами
В большинстве случаев новый режим взаимодействия должен стать полноценной заменой текущему. В будущем мы планируем включить его по умолчанию. Но для этого нужно убедиться, что он работает как можно лучше, и протестировать его на самых разных проектах, поскольку:
Некоторые объявления C и Objective-C пока не поддерживаются в новом режиме (в основном из-за проблем совместимости). Мы хотели бы лучше понять реальные последствия этого и соответствующим образом расставить приоритеты для дальнейших шагов.
Возможны ошибки или недочёты. Тестировать языки с множеством взаимодействующих функций непросто, а тестировать взаимодействие языков (каждый из которых обладает уникальным набором функций) ещё сложнее.
Помогите нам изучить реальные проекты и выявить сложные случаи. Независимо от того, столкнулись ли вы с проблемами, поделитесь результатами в комментариях к задаче в YouTrack.
Kotlin/Wasm
В Kotlin 2.3.20 повышена производительность операций со строками, сокращено время компиляции и уменьшено потребление памяти. Кроме того, добавлена поддержка экспериментальной аннотации @nativeInvoke, которая позволяет вызывать объекты или классы Kotlin как функции JavaScript.
Повышение производительности операций со строками
Теперь Kotlin/Wasm использует встроенные функции строк JS для операций со значениями kotlin.String. Благодаря этому Kotlin/Wasm может использовать оптимизации строк движка JavaScript в браузерах и средах выполнения Wasm, поддерживающих это предложение. Оптимизация применяется к таким операциям, как конкатенация, интерполяция, StringBuilder.append() и преобразование чисел в строки.
Это даёт следующие результаты:
Интерполяция строк в целевых тестах производительности выполняется до 4,6 раза быстрее.
Размер двоичных файлов Wasm в сборке приложения KotlinConf уменьшился примерно на 5%.
Медианный показатель по всем тестам производительности Wasm улучшился примерно на 1%.
В сценариях с интенсивным добавлением данных
StringBuilder.append()и конкатенация экземпляровkotlin.Stringвыполняются как минимум на 20% быстрее.
Сокращение времени компиляции и оптимизация использования памяти
В Kotlin 2.3.20 добавлены оптимизации компилятора, значительно сокращающие потребление памяти во время компиляции, особенно в крупных проектах. Эти оптимизации также повышают производительность инкрементальных сборок.
В ходе тестирования мы зафиксировали сокращение времени чистой сборки на 65% и времени инкрементальной сборки на 21%.
Поддержка аннотации @nativeInvoke
В Kotlin 2.3.20 добавлена поддержка аннотации @nativeInvoke для целевой платформы wasmJs. Эта аннотация позволяет обращаться с объектом или классом Kotlin так, как если бы он был функцией JavaScript. Она предназначена для обозначения функции-члена объявления external (класса или интерфейса) в качестве «оператора вызова» объекта JavaScript.
Если аннотировать функцию, каждый вызов этой функции в Kotlin будет преобразован в прямой вызов самого объекта JavaScript:
import kotlin.js.nativeInvoke
@OptIn(ExperimentalWasmJsInterop::class)
external class JsAction {
@nativeInvoke
operator fun invoke(data: String)
}
fun main() {
val action = JsAction()
action("Run task")
}
Это временное решение, которое будет использоваться до разработки стабильного взаимодействия между Kotlin/Wasm и JavaScript. В будущих выпусках оно может быть изменено или удалено, а при его использовании компилятор выводит предупреждение.
Подробнее о взаимодействии Kotlin/Wasm с JavaScript см. в разделе Взаимодействие с JavaScript.
Kotlin/JS
В Kotlin 2.3.20 появилась возможность реализовывать интерфейсы Kotlin на TypeScript и экспериментальная поддержка платформы компиляции SWC.
Реализация интерфейсов Kotlin на JavaScript/TypeScript
В Kotlin 2.3.20 снято ограничение на реализацию интерфейсов Kotlin на стороне JavaScript/TypeScript. Раньше интерфейсы Kotlin можно было экспортировать в TypeScript только как интерфейсы TypeScript; реализовывать их в TypeScript было запрещено.
Теперь любой интерфейс Kotlin можно реализовать следующим образом:
// Kotlin
@JsExport
interface DataProcessor {
suspend fun process(): String
}
@JsExport
fun registerProcessor(processor: DataProcessor) { ... }
// TypeScript
import { DataProcessor, registerProcessor } from "my-kmp-library"
class JsonProcessor implements DataProcessor {
readonly [DataProcessor.Symbol] = true
async process(): Promise<string> {
return "processed JSON data"
}
}
registerProcessor(new JsonProcessor())
Также можно повторно использовать реализации Kotlin по умолчанию из TypeScript. Хотя в TypeScript нет понятия реализаций по умолчанию в интерфейсах, это ограничение можно обойти, делегируя вызовы объекту DefaultImpls:
// Kotlin
@JsExport
interface Logger {
fun log(): String = "[INFO] Default log entry"
val prefix: String get() = "LOG"
}
// TypeScript
import { Logger, acceptLogger } from "my-kmp-library"
class ConsoleLogger implements Logger {
readonly [Logger.Symbol] = true
// Delegates to the default method implementation
log(): string {
return Logger.DefaultImpls.log(this);
}
// Delegates to the default property implementation
get prefix(): string {
return Logger.DefaultImpls.prefix.get(this);
}
}
acceptLogger(new ConsoleLogger())
Как включить
Добавьте в файл сборки новый параметр компилятора:
kotlin {
js {
// ...
generateTypeScriptDefinitions()
compilerOptions {
freeCompilerArgs.add("-Xenable-implementing-interfaces-from-typescript")
}
}
}
Подробнее см. в разделе аннотация @JsExport.
Поддержка платформы компиляции SWC
Начиная с Kotlin 2.3.20, Kotlin/JS поддерживает платформу компиляции SWC. Она помогает преобразовывать новые версии кода JavaScript/TypeScript в более старый и совместимый код JavaScript.
Передача преобразования кода внешнему инструменту позволяет сократить количество вариантов, создаваемых компилятором Kotlin/JS, и ускорить модернизацию компилятора, сосредоточившись только на поддержке новейших возможностей JavaScript. Сейчас последней поддерживаемой версией ECMAScript по-прежнему является es2015.
Кроме того, передача работы по транспиляции позволяет улучшить функцию встраиваемого JavaScript. Сейчас она поддерживает только синтаксис ES5 (это изменится в версии 2.4.0). Поддержка нового синтаксиса при компиляции для более старых версий была бы сложной задачей, поскольку для этого компилятору пришлось бы транспилировать код JS непосредственно в блоке встроенного JS. С помощью SWC мы сможем добавить современный синтаксис JS, а инструмент преобразует код в синтаксис, необходимый для целевой версии, используемой конечным пользователем.
Переход на SWC также даёт возможность реализовать в плагине Kotlin Gradle DSL на основе browserlist. Это позволит указывать целевые браузеры или среды вместо конкретных версий JS.
Как включить
Добавьте в файл gradle.properties следующий параметр:
kotlin.js.delegated.transpilation=true
В будущих выпусках Kotlin мы планируем стабилизировать транспиляцию с помощью SWC. После того как она станет вариантом по умолчанию, компиляция для нескольких целей JS будет полностью передана компилятором Kotlin/JS транспилятору.
Подробнее о платформе SWC см. в официальной документации.
Gradle
Kotlin 2.3.20 совместим с новыми версиями Gradle и включает изменения компиляции Kotlin/JVM в плагине Kotlin Gradle.
Совместимость с Gradle 9.3.0
Kotlin 2.3.20 полностью совместим с версиями Gradle от 7.6.3 до 9.3.0. Также можно использовать версии Gradle вплоть до последнего выпуска. Однако следует учитывать, что это может привести к предупреждениям об устаревших функциях, а некоторые новые возможности Gradle могут не работать.
Улучшения проверки бинарной совместимости в KGP
В Kotlin 2.2.0 впервые появилась поддержка проверки бинарной совместимости в плагине Kotlin Gradle. В Kotlin 2.3.20 добавлены два улучшения.
Во-первых, в названиях задач Gradle для проверки бинарной совместимости больше нет слова «Legacy». Мы внесли это изменение, поскольку прежнее соглашение об именовании сбивало разработчиков Kotlin с толку:
Прежнее название |
Новое название |
|---|---|
|
|
|
|
|
|
В Kotlin 2.3.20 старые названия задач по-прежнему доступны, чтобы упростить переход на новые.
Во-вторых, если включить проверку бинарной совместимости в проекте, Gradle теперь автоматически запускает задачу checkKotlinAbi при запуске задачи check. Раньше Gradle не запускал задачу checkKotlinAbi, хотя задача check должна запускать все задачи проверки. Это приводило к непоследовательному поведению в проектах Gradle.
Компиляция Kotlin/JVM по умолчанию использует Build tools API
В Kotlin 2.3.20 компиляция Kotlin/JVM в плагине Kotlin Gradle по умолчанию использует Build tools API (BTA). Это изменение внутренней инфраструктуры компиляции ускоряет разработку поддержки компилятора Kotlin в инструментах сборки.
Если вы заметили проблемы, поделитесь отзывом в нашем трекере задач.
Maven
В Kotlin 2.3.20 внесено важное изменение, упрощающее настройку проектов Maven.
Упрощённая настройка проектов Kotlin
В Kotlin 2.3.20 настройка Kotlin в проектах Maven стала проще. Теперь Kotlin поддерживает автоматическую настройку корневых каталогов исходного кода и стандартной библиотеки Kotlin.
Благодаря новой конфигурации при создании нового проекта Kotlin с помощью системы сборки Maven или добавлении Kotlin в существующий проект Java Maven не нужно вручную указывать пути к корневым каталогам исходного кода или добавлять зависимость kotlin-stdlib в файл сборки POM.
Как включить
Добавьте <extensions>true</extensions> в раздел <build><plugins> плагина Kotlin Maven в файл pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>2.4.20</version>
<extensions>true</extensions> <!-- Add this extension -->
</plugin>
</plugins>
</build>
Новые возможности параметра <extensions>:
Регистрация каталогов
src/main/kotlinиsrc/test/kotlinв качестве корневых каталогов исходного кода, если они существуют, но не указаны в конфигурации плагина.Добавление зависимости
kotlin-stdlib, если она ещё не указана явно.
Также можно отказаться от автоматического добавления стандартной библиотеки Kotlin. Для этого добавьте следующее в раздел <properties>:
<project>
<properties>
<!-- Disable smart defaults via property -->
<kotlin.smart.defaults.enabled>false</kotlin.smart.defaults.enabled>
</properties>
</project>
Обратите внимание: это свойство отключает не только автоматическое добавление стандартной библиотеки, но и регистрацию путей к корневым каталогам исходного кода. На другие возможности <extensions> оно не влияет.
Подробнее о настройке проектов Kotlin Maven см. в разделе Настройка проекта Maven.
Build tools API
В Kotlin 2.3.20 внесены дополнительные изменения для разработчиков, которые хотят интегрировать свои системы сборки с компилятором Kotlin с помощью Build tools API (BTA).
Улучшения операций сборки
В этом выпуске BTA улучшает управление операциями сборки в инструментах сборки. Операции сборки позволяют инструментам сборки взаимодействовать с компилятором Kotlin. Каждая операция сборки представляет собой реализацию интерфейса BuildOperation.
Теперь можно отменять операции сборки, реализующие интерфейс CancellableBuildOperation, с помощью функции cancel().
Функция cancel() работает по принципу «по возможности». Это означает, что отмена операции не гарантируется.
Например:
val operation = toolchains.jvm.jvmCompilationOperationBuilder(sources, destination) {}
toolchains.createBuildSession().use {
try {
it.executeOperation(operation.build())
} catch (e: OperationCancelledException) {
println("Build operation has been cancelled.")
}
}
// ...
// From another thread:
operation.cancel()
Кроме того, операции сборки стали надёжнее: теперь их можно создавать так, чтобы после запуска их нельзя было изменить. Для этого инструмент сборки должен использовать шаблон проектирования «строитель»:
Настройте объект с помощью изменяемого строителя.
Вызовите функцию
build(), чтобы создать неизменяемый экземпляр объекта.
Например:
fun prepareBuildOperation(toolchains: KotlinToolchains, sources: List<Path>, destination: Path): JvmCompilationOperation {
val builder = toolchains.jvm.jvmCompilationOperationBuilder(sources, destination)
// Configure the operation using the builder
builder.compilerArguments[CommonToolArguments.VERBOSE] = true
builder[COMPILER_ARGUMENTS_LOG_LEVEL] = CompilerArgumentsLogLevel.ERROR
// Return an immutable operation
return builder.build()
}
Единообразный сбор метрик в разных инструментах сборки
До Kotlin 2.3.20 инфраструктура метрик сборки была ориентирована на Gradle, что влияло на такие её части, как названия метрик. Кроме того, не все метрики были доступны для разных стратегий выполнения компилятора.
В Kotlin 2.3.20 BTA обеспечивает сбор метрик для JVM, не зависящий от инструмента сборки. BTA также предоставляет единый набор метрик независимо от стратегии выполнения компилятора. Метрики, относящиеся к конкретному способу компиляции или стратегии выполнения компилятора, предоставляются только в соответствующих случаях. Например, метрики инкрементальной компиляции доступны только для инкрементальных сборок, а метрики, относящиеся к демону, — только при использовании демона Kotlin.
Теперь инструменты сборки могут настроить объект BuildMetricsCollector для операции сборки, чтобы собирать метрики, помогающие пользователям оценить производительность сборки:
val operation =
kotlinToolchains.jvm.jvmCompilationOperationBuilder(sources, outputDirectory)
operation[BuildOperation.METRICS_COLLECTOR] = object : BuildMetricsCollector {
override fun collectMetric(
name: String,
type: BuildMetricsCollector.ValueType,
value: Long
) {
// ...
}
}
Упрощённая настройка плагинов компилятора с помощью инструментов сборки
В Kotlin 2.3.20 BTA предоставляет новый, более простой способ настройки плагинов компилятора средствами сборки. Такой подход позволяет инструментам сборки напрямую передавать конфигурацию пользователям.
Вместо настройки плагинов компилятора через командную строку с помощью экспериментальных параметров компилятора инструменты сборки могут использовать параметр kotlin.buildtools.api.arguments.CommonCompilerArguments.COMPILER_PLUGINS для настройки списка объектов, представляющих конфигурации плагинов компилятора:
Несовместимые изменения и устаревшие возможности
В этом разделе описаны важные несовместимые изменения и устаревшие возможности. Подробнее об устаревших возможностях в Kotlin 2.3.0 и 2.3.20 см. в руководстве по совместимости.
-
В Kotlin 2.3.20 инициализация модуля выполняется при создании экземпляра модуля Wasm, а не после этого с помощью внешнего кода JavaScript, вызывающего функцию
_initialize(). Это изменение делает Kotlin/Wasm более независимым и подготавливает его к предложению по интеграции модулей ES.Если вы используете аннотацию
@EagerInitialization, связанный с ней код может завершиться с ошибкой, если выполнится до завершения инициализации модуля. Рекомендуем не использовать аннотацию@EagerInitializationбез крайней необходимости. Экспериментальные контекстные получатели больше не поддерживаются и заменены на контекстные параметры.
-
Этот выпуск продолжает цикл устаревания целевых платформ Apple на базе чипов Intel. Начиная с Kotlin 2.3.20, объявлены устаревшими целевые платформы
macosX64,tvosX64иwatchosX64. В следующем выпуске Kotlin мы планируем полностью прекратить поддержку этих целевых платформ.Поскольку многие сторонние библиотеки по-прежнему зависят от целевой платформы
iosX64, пока она останется в третьем уровне поддержки. Это означает, что мы не гарантируем тестирование в CI и можем не обеспечивать совместимость исходного и двоичного кода между разными выпусками компилятора. Подробнее об уровнях поддержки см. в разделе Поддержка целевых платформ Kotlin/Native. В Kotlin 2.3.20 более строгая проверка соответствия зависимостей в Kotlin Multiplatform может приводить к ошибкам компиляции метаданных, если разрешение зависимостей различается для общих и платформенных наборов исходного кода. Подробнее об этой проблеме и обходном решении см. задачу в YouTrack.
Обновления документации
В экосистеме Kotlin мы внесли следующие изменения в документацию:
Дорожная карта Kotlin – Ознакомьтесь с обновленным списком приоритетов развития языка и экосистемы Kotlin.
Переход на AGP 9 – Ознакомьтесь с рекомендациями по переносу многоплатформенных проектов с приложениями для Android на AGP 9.
Настройка CI для приложения KMP – Следуйте руководству по настройке GitHub Actions для непрерывной интеграции в многоплатформенном проекте.
Предварительный просмотр интерфейса Compose – Узнайте, как просматривать компонуемые функции в IDE, не запуская эмулятор.
Работа с веб-ресурсами – Узнайте, как работать с веб-ресурсами в Compose Multiplatform.
Настройка области просмотра – Узнайте, как использовать функцию
ComposeViewport()для отображения интерфейса на холсте HTML с помощью Compose Multiplatform для веба.Пользовательские плагины компилятора – Узнайте, как работают плагины компилятора и что делать, если не удается найти плагин, подходящий для вашего случая.
Структура приложения – Выберите оптимальную структуру приложения для Ktor Server.
Жизненный цикл HTTP-запроса – Узнайте, как отменить обработку запроса в Ktor при отключении клиента, используя жизненный цикл HTTP-запроса.
Внедрение зависимостей – Узнайте, как настроить внедрение зависимостей в Ktor Server, ознакомьтесь с обновленными рекомендациями и практическими примерами.
Интеграция Exposed со Spring Boot – Узнайте, как использовать Exposed со Spring Boot 3 и 4.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/whatsnew2320.html