Spec-Zone.ru › Kotlin 1.9

Что нового в Kotlin 1.8.0

Выпущено: 28 декабря 2022 года

Вышел релиз Kotlin 1.8.0, и вот некоторые из его ключевых особенностей:

  • Новые экспериментальные функции для JVM: рекурсивное копирование или удаление содержимого каталога

  • Улучшенная производительность kotlin-reflect

  • Новая опция компилятора -Xdebug для лучшего опыта отладки

  • kotlin-stdlib-jdk7 и kotlin-stdlib-jdk8 объединены в kotlin-stdlib

  • Улучшенная взаимозаменяемость Objective-C/Swift

  • Совместимость с Gradle 7.3

Поддержка IDE

Плагин Kotlin, поддерживающий 1.8.0, доступен для:

IDE

Поддерживаемые версии

IntelliJ IDEA

2021.3, 2022.1, 2022.2

Android Studio

Electric Eel (221), Flamingo (222)

Вы можете обновить свои проекты до Kotlin 1.8.0 в IntelliJ IDEA 2022.3 без обновления плагина IDE.

Для миграции существующих проектов в Kotlin 1.8.0 в IntelliJ IDEA 2022.3 измените версию Kotlin на 1.8.0 и повторно импортируйте свой проект Gradle или Maven.

Kotlin/JVM

Начиная с версии 1.8.0, компилятор может генерировать классы с версией байткода, соответствующей JVM 19. Новая версия языка также включает:

  • Опция компилятора для отключения генерации целевых аннотаций JVM

  • Новая опция компилятора -Xdebug для отключения оптимизаций

  • Удаление старого бэкенда

  • Поддержка аннотации Lombok @Builder

Возможность не генерировать целевые аннотации TYPE_USE и TYPE_PARAMETER

Если Kotlin аннотация имеет TYPE среди своих Kotlin целей, аннотация отображается на java.lang.annotation.ElementType.TYPE_USE в списке Java целевых аннотаций. Это аналогично тому, как TYPE_PARAMETER Kotlin цель отображается на java.lang.annotation.ElementType.TYPE_PARAMETER Java целевую аннотацию. Это проблема для Android клиентов с уровнями API меньше 26, которые не имеют этих целей в API.

Начиная с Kotlin 1.8.0, вы можете использовать новую опцию компилятора -Xno-new-java-annotation-targets для избежания генерации TYPE_USE и TYPE_PARAMETER целевых аннотаций.

Новая опция компилятора для отключения оптимизаций

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

Функция «был оптимизирован» оптимизирует переменные при использовании приостановленных функций. Однако отладка кода с оптимизированными переменными затруднена, поскольку их значения не отображаются.

Никогда не используйте эту опцию в производстве: Отключение этой функции с помощью -Xdebug может вызвать утечки памяти.

Удаление старого бэкенда

В Kotlin 1.5.0 мы сообщили, что бэкенд на основе IR стал стабильным. Это означало, что старый бэкенд из Kotlin 1.4.* был устаревшим. В Kotlin 1.8.0 мы полностью удалили старый бэкенд. Вследствие этого, мы удалили опцию компилятора -Xuse-old-backend и опцию Gradle useOldBackend.

Поддержка аннотации Lombok @Builder

Сообщество добавило множество голосов по вопросу Kotlin Lombok: Поддержка сгенерированных билдеров (@Builder) в YouTrack, поэтому мы просто должны поддержать @Builder аннотацию.

Пока у нас нет планов по поддержке аннотаций @SuperBuilder или @Tolerate, но мы пересмотрим это, если достаточно людей проголосуют за проблемы @SuperBuilder и @Tolerate.

Узнайте, как настроить плагин компилятора Lombok.

Kotlin/Native

Kotlin 1.8.0 включает изменения в межплатформенной работе с Objective-C и Swift, поддержку Xcode 14.1 и улучшения плагина CocoaPods Gradle:

  • Поддержка Xcode 14.1

  • Улучшенная межплатформенная работа Objective-C/Swift

  • Динамические фреймворки по умолчанию в плагине CocoaPods Gradle

Поддержка Xcode 14.1

Компилятор Kotlin/Native теперь поддерживает последнюю стабильную версию Xcode, 14.1. Улучшения совместимости включают следующие изменения:

  • Добавлен новый watchosDeviceArm64 предустановленный набор для целевой платформы watchOS, поддерживающий Apple watchOS на платформах ARM64.

  • Плагин Kotlin CocoaPods Gradle больше не включает встраивание bitcode для фреймворков Apple по умолчанию.

  • Библиотеки платформы были обновлены в соответствии с изменениями в фреймворках Objective-C для целевых платформ Apple.

Улучшенная межплатформенная работа Objective-C/Swift

Для повышения межплатформенной совместимости Kotlin с Objective-C и Swift были добавлены три новые аннотации:

  • @ObjCName позволяет указать более понятное имя на Swift или Objective-C вместо переименования объявления Kotlin.

    Аннотация инструктирует компилятор Kotlin использовать пользовательское имя Objective-C и Swift для этого класса, свойства, параметра или функции:

    @ObjCName(swiftName = "MySwiftArray")
    class MyKotlinArray {
        @ObjCName("index")
        fun indexOf(@ObjCName("of") element: String): Int = TODO()
    }
    
    // Usage with the ObjCName annotations
    let array = MySwiftArray()
    let index = array.index(of: "element")
    
  • @HiddenFromObjC позволяет скрыть объявление Kotlin от Objective-C.

    Аннотация инструктирует компилятор Kotlin не экспортировать функцию или свойство в Objective-C и, следовательно, в Swift. Это может сделать ваш код Kotlin более дружественным для Objective-C/Swift.

  • @ShouldRefineInSwift полезна для замены объявления Kotlin оберточным кодом, написанным на Swift.

    Аннотация инструктирует компилятор Kotlin пометить функцию или свойство как swift_private в сгенерированном API Objective-C. Такие объявления получают префикс __, что делает их невидимыми для кода Swift.

    Вы по-прежнему можете использовать эти объявления в своем коде Swift для создания API, удобного для Swift, но они не будут предлагаться автодополнением Xcode, например.

    Для получения дополнительной информации об уточнении объявлений Objective-C в Swift, см. официальную документацию Apple.

Новые аннотации требуют включении поддержки.

Команда Kotlin выражает огромную благодарность Рику Клефасу за реализацию этих аннотаций.

Динамические фреймворки по умолчанию в плагине CocoaPods Gradle

Начиная с Kotlin 1.8.0, фреймворки Kotlin, зарегистрированные плагином CocoaPods Gradle, по умолчанию подключаются динамически. Предыдущая статическая реализация была несовместима с поведением плагина Kotlin Gradle.

kotlin {
    cocoapods {
        framework {
            baseName = "MyFramework"
            isStatic = false // Now dynamic by default
        }
    }
}

Если у вас есть существующий проект со статическим типом подключения и вы обновляетесь до Kotlin 1.8.0 (или явно меняете тип подключения), вы можете столкнуться с ошибкой выполнения проекта. Чтобы исправить ее, закройте проект Xcode и запустите pod install в каталоге Podfile.

Дополнительную информацию см. в справочнике по DSL плагина CocoaPods Gradle.

Kotlin Multiplatform: Новая структура наборов ресурсов Android

Kotlin 1.8.0 вводит новую структуру наборов ресурсов Android, которая заменяет предыдущую схему именования каталогов, вызывающую неоднозначность.

Рассмотрим пример двух androidTest каталогов, созданных в текущей структуре. Один для KotlinSourceSets, а другой для AndroidSourceSets:

  • Они имеют разные семантики: androidTest Kotlin принадлежит типу unitTest, в то время как Android принадлежит типу integrationTest.

  • Они создают запутанную SourceDirectories структуру, так как src/androidTest/kotlin имеет UnitTest, а src/androidTest/java имеет InstrumentedTest.

  • И KotlinSourceSets и AndroidSourceSets используют похожую схему именования конфигураций Gradle, поэтому результирующие конфигурации androidTest для наборов ресурсов Kotlin и Android одинаковы: androidTestImplementation, androidTestApi, androidTestRuntimeOnly и androidTestCompileOnly.

Для решения этих и других существующих проблем мы представили новую структуру наборов ресурсов Android. Вот некоторые ключевые различия между двумя структурами:

Схема именования KotlinSourceSet

Текущая структура набора ресурсов

Новая структура набора ресурсов

targetName + AndroidSourceSet.name

targetName + AndroidVariantType

{AndroidSourceSet.name} отображается на {KotlinSourceSet.name} следующим образом:

Текущая структура набора ресурсов

Новая структура набора ресурсов

main

androidMain

androidMain

test

androidTest

androidUnitTest

androidTest

androidAndroidTest

androidInstrumentedTest

Директории наборов ресурсов

Текущая структура набора ресурсов

Новая структура набора ресурсов

Структура добавляет дополнительные /kotlin директории наборов ресурсов

src/{AndroidSourceSet.name}/kotlin, src/{KotlinSourceSet.name}/kotlin

{AndroidSourceSet.name} отображается на {SourceDirectories included} следующим образом:

Текущая структура набора ресурсов

Новая структура набора ресурсов

main

src/androidMain/kotlin, src/main/kotlin, src/main/java

src/androidMain/kotlin, src/main/kotlin, src/main/java

test

src/androidTest/kotlin, src/test/kotlin, src/test/java

src/androidUnitTest/kotlin, src/test/kotlin, src/test/java

androidTest

src/androidAndroidTest/kotlin, src/androidTest/java

src/androidInstrumentedTest/kotlin, src/androidTest/java, src/androidTest/kotlin

Расположение файла AndroidManifest.xml

Текущая структура набора ресурсов

Новая структура набора ресурсов

src/{AndroidSourceSet.name}/AndroidManifest.xml

src/{KotlinSourceSet.name}/AndroidManifest.xml

{AndroidSourceSet.name} отображается на {AndroidManifest.xml location} следующим образом:

Текущая структура набора ресурсов

Новая структура набора ресурсов

main

src/main/AndroidManifest.xml

src/androidMain/AndroidManifest.xml

debug

src/debug/AndroidManifest.xml

src/androidDebug/AndroidManifest.xml

Взаимодействие между Android и общими тестами

Новая структура набора ресурсов Android изменяет взаимосвязь между Android-тестами (переименованными в androidInstrumentedTest в новой структуре) и общими тестами.

Ранее существовала стандартная dependsOn связь между androidAndroidTest и commonTest. На практике это означало следующее:

  • Код в commonTest был доступен в androidAndroidTest.

  • Объявления expect в commonTest должны были иметь соответствующие реализации actual в androidAndroidTest.

  • Тесты, объявленные в commonTest также выполнялись как Android-тесты.

В новой структуре набора ресурсов Android эта dependsOn связь не добавляется по умолчанию. Если вы предпочитаете прежнее поведение, вручную объявите эту связь в вашем файле build.gradle.kts:

kotlin {
// ...
    sourceSets {
        val commonTest by getting
        val androidInstrumentedTest by getting {
            dependsOn(commonTest)
        }
    }
}

Поддержка Android-наборов ресурсов

Ранее плагин Kotlin Gradle с готовностью создавал наборы ресурсов, соответствующие Android-наборам ресурсов с типами сборки debug и release или настраиваемыми наборами ресурсов, такими как demo и full. Они были доступны с помощью конструкций, таких как val androidDebug by getting { ... }.

В новой структуре набора ресурсов Android эти наборы ресурсов создаются на стадии afterEvaluate Это делает такие выражения недействительными, что приводит к ошибкам, подобным org.gradle.api.UnknownDomainObjectException: KotlinSourceSet with name 'androidDebug' not found.

Для решения этой проблемы используйте новый API invokeWhenCreated() в вашем файле build.gradle.kts:

kotlin {
// ...
    sourceSets.invokeWhenCreated("androidFreeDebug") {
        // ...
    }
}

Настройка

Новая структура станет по умолчанию в будущих версиях. Вы можете включить её сейчас с помощью следующей опции Gradle:

kotlin.mpp.androidSourceSetLayoutVersion=2

Новая структура требует Android Gradle Plugin 7.0 или более поздней версии и поддерживается в Android Studio 2022.3 и более поздних версиях.

Использование предыдущих каталогов в стиле Android не рекомендуется. Kotlin 1.8.0 отмечает начало процесса устаревания, вызывая предупреждение для текущей структуры. Вы можете подавить это предупреждение с помощью следующего свойства Gradle:

kotlin.mpp.androidSourceSetLayoutVersion1.nowarn=true

Kotlin/JS

Kotlin 1.8.0 стабилизирует бэкенд компилятора JS IR и добавляет новые возможности в скрипты сборки Gradle, связанные с JavaScript:

  • Стабильный бэкенд компилятора JS IR

  • Новые настройки для отчётности об обновлении yarn.lock

  • Добавление целей тестирования для браузеров через свойства Gradle

  • Новый подход к добавлению поддержки CSS в ваш проект

Стабильный бэкенд компилятора JS IR

Начиная с этого релиза, бэкенд компилятора Kotlin/JS промежуточного представления (IR-основанного) является стабильным. На унификацию инфраструктуры для всех трёх бэкендов потребовалось время, но теперь они работают с одним и тем же IR для кода Kotlin.

Вследствие стабильного бэкенда компилятора JS IR, старый бэкенд теперь устарел.

Инкрементная компиляция включена по умолчанию вместе со стабильным JS IR компилятором.

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

Новые настройки для отчётности об обновлении yarn.lock

Если вы используете менеджер пакетов yarn, есть три новые специальные настройки Gradle, которые могут уведомить вас, если файл yarn.lock был обновлён. Вы можете использовать эти настройки, когда хотите быть уведомлёнными, если yarn.lock был изменён в процессе сборки CI.

Эти три новые свойства Gradle:

  • YarnLockMismatchReport, которое определяет, как будут сообщаться изменения в файле yarn.lock. Вы можете использовать одно из следующих значений:

    • FAIL — соответствующая задача Gradle завершается неудачно. Это значение по умолчанию.

    • WARNING — информация об изменениях записывается в журнал предупреждений.

    • NONE — отчётность отключена.

  • reportNewYarnLock, которое явно сообщает об недавно созданном файле yarn.lock. По умолчанию этот параметр отключён: обычно новый файл yarn.lock генерируется при первом запуске. Вы можете использовать этот параметр, чтобы убедиться, что файл добавлен в ваш репозиторий.

  • yarnLockAutoReplace, который автоматически заменяет yarn.lock каждый раз при выполнении задачи Gradle.

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

import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension

rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
    rootProject.the<YarnRootExtension>().yarnLockMismatchReport =
        YarnLockMismatchReport.WARNING // NONE | FAIL
    rootProject.the<YarnRootExtension>().reportNewYarnLock = false // true
    rootProject.the<YarnRootExtension>().yarnLockAutoReplace = false // true
}

Добавление целей тестирования для браузеров через свойства Gradle

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

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

Например, следующая строка в файле свойств Gradle запустит тесты в Firefox и Safari для всех модулей:

kotlin.js.browser.karma.browsers=firefox,safari

Полный список доступных значений для свойства на GitHub.

Команда Kotlin выражает благодарность Martynas Petuška за реализацию этой функции.

Новый подход к добавлению поддержки CSS в ваш проект

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

До Kotlin 1.8.0, для добавления поддержки CSS использовалось свойство cssSupport.enabled.

browser {
    commonWebpackConfig {
        cssSupport.enabled = true
    }
}

Теперь вы должны использовать метод enabled.set() в блоке cssSupport {}:

browser {
    commonWebpackConfig {
        cssSupport {
            enabled.set(true)
        }
    }
}

Gradle

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

Эта версия включает множество изменений:

  • Экспонирование параметров компилятора Kotlin как ленивых свойств Gradle

  • Повышение минимально поддерживаемых версий

  • Возможность отключения стратегии резервного копирования демона Kotlin

  • Использование последней версии kotlin-stdlib в транзитивных зависимостях

  • Обязательная проверка равенства совместимости целевых JVM связанных задач компиляции Kotlin и Java

  • Разрешение транзитивных зависимостей плагинов Kotlin Gradle

  • Устаревания и удаления

Экспонирование параметров компилятора Kotlin как ленивых свойств Gradle

Для экспонирования доступных параметров компилятора Kotlin как ленивых свойств Gradle и для лучшей интеграции их в задачи Kotlin, мы внесли множество изменений:

  • Задачи компиляции имеют новый compilerOptions ввод, аналогичный существующему kotlinOptions, но использующий Property из API свойств Gradle в качестве типа возвращаемого значения:

    tasks.named("compileKotlin", org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile::class.java) {
        compilerOptions {
            useK2.set(true)
        }
    }
    
  • Задачи инструментов Kotlin KotlinJsDce и KotlinNativeLink имеют новый toolOptions ввод, аналогичный существующему kotlinOptions вводу.

  • Новые вводы имеют @Nested аннотацию Gradle. Каждое свойство внутри вводов имеет связанную аннотацию Gradle, такую как @Input или @Internal.

  • Артефакт API плагина Kotlin Gradle содержит два новых интерфейса:

    • org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask, который имеет compilerOptions ввод и compileOptions() метод. Все задачи компиляции Kotlin реализуют этот интерфейс.

    • org.jetbrains.kotlin.gradle.tasks.KotlinToolTask, который имеет toolOptions ввод и toolOptions() метод. Все задачи инструментов Kotlin – KotlinJsDce, KotlinNativeLink, и KotlinNativeLinkArtifactTask – реализуют этот интерфейс.

  • Некоторые compilerOptions используют новые типы вместо типа String.

    • JvmTarget

    • KotlinVersion (для вводов apiVersion и languageVersion)

    • JsMainFunctionExecutionMode

    • JsModuleKind

    • JsSourceMapEmbedMode

    Например, вы можете использовать compilerOptions.jvmTarget.set(JvmTarget.JVM_11) вместо kotlinOptions.jvmTarget = "11".

    Типы kotlinOptions не изменились и внутри преобразуются в типы compilerOptions.

  • API плагина Kotlin Gradle бинарно совместим с предыдущими выпусками. Однако, в артефакте kotlin-gradle-plugin есть некоторые изменения, нарушающие исходный код и ABI. Большинство этих изменений связаны с добавлением дополнительных универсальных параметров к некоторым внутренним типам. Важное изменение состоит в том, что задача KotlinNativeLink больше не наследует задачу AbstractKotlinNativeCompile.

  • KotlinJsCompilerOptions.outputFile и связанные с ними параметры KotlinJsOptions.outputFile устарели. Используйте вход Kotlin2JsCompile.outputFileProperty задачи вместо этого.

Плагин Kotlin Gradle по-прежнему добавляет KotlinJvmOptions DSL к расширению Android:

android { 
    kotlinOptions {
        jvmTarget = "11"
    }
}

Это будет изменено в рамках этого вопроса, когда compilerOptions DSL будет добавлен на уровне модуля.

Ограничения

Ввод kotlinOptions задачи и DSL задачи kotlinOptions{...} находятся в режиме поддержки и будут устаревать в будущих выпусках. Улучшения будут внесены только для compilerOptions и toolOptions.

Вызов любого метода set или get на kotlinOptions делегирует соответствующему свойству в compilerOptions. Это приводит к следующим ограничениям:

  • compilerOptions и kotlinOptions не могут быть изменены на фазе выполнения задачи (есть одно исключение в абзаце ниже).

  • freeCompilerArgs возвращает неизменяемый List<String>, что означает, например, что kotlinOptions.freeCompilerArgs.remove("something") потерпит неудачу.

Несколько плагинов, включая kotlin-dsl и плагин Android Gradle (AGP) с включенным Jetpack Compose, пытаются изменить атрибут freeCompilerArgs на фазе выполнения задачи. Мы добавили обходной путь для них в Kotlin 1.8.0. Этот обходной путь позволяет любому скрипту сборки или плагину изменять kotlinOptions.freeCompilerArgs на фазе выполнения, но генерирует предупреждение в журнале сборки. Чтобы отключить это предупреждение, используйте новое свойство Gradle kotlin.options.suppressFreeCompilerArgsModificationWarning=true. Gradle добавит исправления для kotlin-dsl плагина и AGP с включенным Jetpack Compose.

Повышение минимально поддерживаемых версий

Начиная с Kotlin 1.8.0, минимально поддерживаемая версия Gradle — 6.8.3, а минимально поддерживаемая версия плагина Android Gradle — 4.1.3.

См. совместимость плагина Kotlin Gradle с доступными версиями Gradle в нашей документации.

Возможность отключения стратегии резервного копирования демона Kotlin

Есть новое свойство Gradle kotlin.daemon.useFallbackStrategy, значение которого по умолчанию true. Когда значение равно false, сборка завершается ошибкой при проблемах с запуском или обменом данными демона. Также есть новое свойство useDaemonFallbackStrategy в задачах компиляции Kotlin, которое имеет приоритет над свойством Gradle, если вы используете оба. Если памяти недостаточно для выполнения компиляции, в журналах появится соответствующее сообщение.

Стратегия резервного копирования компилятора Kotlin — запуск компиляции вне демона Kotlin, если по какой-то причине демон не работает. Если демон Gradle включен, компилятор использует стратегию «В процессе». Если демон Gradle выключен, компилятор использует стратегию «Вне процесса». Узнайте больше о стратегиях выполнения в документации. Обратите внимание, что пассивное резервное копирование другой стратегии может потреблять много системных ресурсов или привести к невоспроизводимым сборкам; см. эту задачу YouTrack для получения дополнительной информации.

Использование последней версии kotlin-stdlib в зависимостях транзитивных зависимостей

Если вы явно укажете версию Kotlin 1.8.0 или выше в своих зависимостях, например: implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.0"), то плагин Kotlin Gradle будет использовать эту версию Kotlin для транзитивных kotlin-stdlib-jdk7 и kotlin-stdlib-jdk8 зависимостей. Это делается для предотвращения дублирования классов из разных версий stdlib (подробнее о слиянии kotlin-stdlib-jdk7 и kotlin-stdlib-jdk8 в kotlin-stdlib). Вы можете отключить это поведение с помощью свойства Gradle kotlin.stdlib.jdk.variants.version.alignment.

kotlin.stdlib.jdk.variants.version.alignment=false

Если у вас возникнут проблемы с согласованием версий, согласуйте все версии с помощью Kotlin BOM, объявив плаформенную зависимость от kotlin-bom в вашем скрипте сборки:

implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))

Узнайте о других случаях и наших рекомендуемых решениях в документации.

Обязательная проверка JVM-целей связанных задач компиляции Kotlin и Java

Этот раздел применим к вашим JVM-проектам, даже если ваши исходные файлы только на Kotlin и вы не используете Java.

Начиная с этого выпуска, значение по умолчанию для kotlin.jvm.target.validation.mode свойства равно error для проектов на Gradle 8.0+ (эта версия Gradle еще не выпущена), и плагин будет прерывать сборку при несовместимости JVM-целей.

Переход значения по умолчанию от warning к error — это подготовительный шаг для плавной миграции на Gradle 8.0. Рекомендуется установить это свойство в error и настроить инструмент сборки или вручную согласовать версии JVM.

Узнайте больше о том, что может пойти не так, если не проверить совместимость целей.

Разрешение транзитивных зависимостей плагинов Kotlin Gradle

В Kotlin 1.7.0 мы добавили поддержку вариантов плагинов Gradle. Из-за этих вариантов плагинов, класс сборки может иметь разные версии плагинов Kotlin Gradle, которые зависят от разных версий некоторой зависимости, обычно kotlin-gradle-plugin-api. Это может привести к проблеме разрешения, и мы хотели бы предложить следующее решение, используя плагин kotlin-dsl в качестве примера.

Плагин kotlin-dsl в Gradle 7.6 зависит от плагина org.jetbrains.kotlin.plugin.sam.with.receiver:1.7.10, который зависит от kotlin-gradle-plugin-api:1.7.10. Если вы добавите плагин org.jetbrains.kotlin.gradle.jvm:1.8.0, эта транзитивная зависимость kotlin-gradle-plugin-api:1.7.10 может привести к ошибке разрешения зависимостей из-за несоответствия версий (1.8.0 и 1.7.10) и значений атрибутов варианта org.gradle.plugin.api-version. В качестве решения добавьте эту ограничение для согласования версий. Это решение может потребоваться до тех пор, пока мы не реализуем платформу согласования библиотек плагинов Kotlin Gradle, что запланировано:

dependencies {
    constraints {
        implementation("org.jetbrains.kotlin:kotlin-sam-with-receiver:1.8.0")
    }
}

Это ограничение принуждает использовать версию org.jetbrains.kotlin:kotlin-sam-with-receiver:1.8.0 в пути сборки для транзитивных зависимостей. Узнайте больше об одном аналогичном случае в трекере проблем Gradle.

Устаревшие и удалённые элементы

В Kotlin 1.8.0 цикл устаревания продолжается для следующих свойств и методов:

  • В примечаниях к Kotlin 1.7.0 отмечалось, что задача KotlinCompile по-прежнему содержала устаревшее свойство Kotlin classpath, которое будет удалено в будущих версиях. Теперь мы изменили уровень устаревания на error для свойства classpath задачи KotlinCompile. Все задачи компиляции используют вход libraries для списка библиотек, необходимых для компиляции.

  • Мы удалили свойство kapt.use.worker.api, которое позволяло запускать kapt через Gradle Workers API. По умолчанию kapt использует Gradle workers с Kotlin 1.3.70, и мы рекомендуем придерживаться этого метода.

  • В Kotlin 1.7.0 мы объявили о начале цикла устаревания для свойства kotlin.compiler.execution.strategy. В этом выпуске мы удалили это свойство. Узнайте, как определить стратегию выполнения Kotlin-компилятора другими способами.

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

Kotlin 1.8.0:

  • Обновлён целевой JVM-компилятор целевой JVM-компилятор.

  • Стабилизированы ряд функций – преобразование единиц времени между Java и Kotlin, cbrt(), Java Optionals расширяющие функции.

  • Представлен превью сравнимых и вычитаемых TimeMarks.

  • Включены экспериментальные расширяющие функции для рекурсивного копирования или удаления каталогов.

  • Представлено улучшенное производительность kotlin-reflect.

Обновлённая целевая JVM-компиляция

В Kotlin 1.8.0 стандартные библиотеки (kotlin-stdlib, kotlin-reflect, и kotlin-script-*) скомпилированы с целевым JVM 1.8. Ранее стандартные библиотеки компилировались с целевым JVM 1.6.

Kotlin 1.8.0 больше не поддерживает JVM-целевые версии 1.6 и 1.7. В результате, вам больше не нужно объявлять kotlin-stdlib-jdk7 и kotlin-stdlib-jdk8 отдельно в скриптах сборки, так как содержимое этих артефактов объединены в kotlin-stdlib.

Если вы явно объявили kotlin-stdlib-jdk7 и kotlin-stdlib-jdk8 в качестве зависимостей в скриптах сборки, замените их на kotlin-stdlib.

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

cbrt()

Функция cbrt(), позволяющая вычислить действительный кубический корень из double или float, теперь стабильна.

import kotlin.math.*

fun main() {
    val num = 27
    val negNum = -num

    println("The cube root of ${num.toDouble()} is: " +
            cbrt(num.toDouble()))
    println("The cube root of ${negNum.toDouble()} is: " +
            cbrt(negNum.toDouble()))
}

Преобразование единиц времени между Java и Kotlin

Функции toTimeUnit() и toDurationUnit() в kotlin.time теперь стабильны. Введённые как экспериментальные в Kotlin 1.6.0, эти функции улучшают взаимодействие между Kotlin и Java. Теперь вы можете легко преобразовывать между Java java.util.concurrent.TimeUnit и Kotlin kotlin.time.DurationUnit. Эти функции поддерживаются только на JVM.

import kotlin.time.*

// For use from Java
fun wait(timeout: Long, unit: TimeUnit) {
    val duration: Duration = timeout.toDuration(unit.toDurationUnit())
    ...
}

Сравнимые и вычитаемые отметки времени

Новая функциональность TimeMarks является экспериментальной, и для её использования необходимо включить её, используя @OptIn(ExperimentalTime::class) или @ExperimentalTime.

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

Для решения этой проблемы в Kotlin 1.8.0 вы можете вычитать и сравнивать TimeMarks из одного и того же источника времени. Теперь вы можете создать новый экземпляр TimeMark для представления текущего момента и вычитать другие TimeMarks из него. Таким образом, результаты, которые вы собираете из этих вычислений, гарантированно будут относительны друг к другу.

import kotlin.time.*
fun main() {
//sampleStart
    val timeSource = TimeSource.Monotonic
    val mark1 = timeSource.markNow()
    Thread.sleep(500) // Sleep 0.5 seconds
    val mark2 = timeSource.markNow()

    // Before 1.8.0
    repeat(4) { n ->
        val elapsed1 = mark1.elapsedNow()
        val elapsed2 = mark2.elapsedNow()

        // Difference between elapsed1 and elapsed2 can vary depending 
        // on how much time passes between the two elapsedNow() calls
        println("Measurement 1.${n + 1}: elapsed1=$elapsed1, " +
                "elapsed2=$elapsed2, diff=${elapsed1 - elapsed2}")
    }
    println()

    // Since 1.8.0
    repeat(4) { n ->
        val mark3 = timeSource.markNow()
        val elapsed1 = mark3 - mark1
        val elapsed2 = mark3 - mark2

        // Now the elapsed times are calculated relative to mark3, 
        // which is a fixed value
        println("Measurement 2.${n + 1}: elapsed1=$elapsed1, " +
                "elapsed2=$elapsed2, diff=${elapsed1 - elapsed2}")
    }
    // It's also possible to compare time marks with each other
    // This is true, as mark2 was captured later than mark1
    println(mark2 > mark1)
//sampleEnd
}

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

Рекурсивное копирование или удаление каталогов

Эти новые функции для java.nio.file.path являются экспериментальными. Для их использования необходимо включить их с помощью @OptIn(kotlin.io.path.ExperimentalPathApi::class) или @kotlin.io.path.ExperimentalPathApi. В качестве альтернативы, вы можете использовать опцию компилятора -opt-in=kotlin.io.path.ExperimentalPathApi.

Мы представили две новые расширяющие функции для java.nio.file.Path, copyToRecursively() и deleteRecursively(), которые позволяют вам рекурсивно:

  • Скопировать каталог и его содержимое в другое место назначения.

  • Удалить каталог и его содержимое.

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

Обработка ошибок

Используя copyToRecursively(), вы можете определить, что должно произойти, если возникнет исключение во время копирования, перегрузив лямбда-функцию onError:

sourceRoot.copyToRecursively(destinationRoot, followLinks = false,
    onError = { source, target, exception ->
        logger.logError(exception, "Failed to copy $source to $target")
        OnErrorResult.TERMINATE
    })

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

Перезапись файла

Если copyToRecursively() обнаружит, что файл уже существует в целевом каталоге, произойдет исключение. Если вы хотите перезаписать файл, используйте перегрузку, имеющую overwrite в качестве аргумента и установите его в true:

fun setUpEnvironment(projectDirectory: Path, fixtureName: String) {
    fixturesRoot.resolve(COMMON_FIXTURE_NAME)
        .copyToRecursively(projectDirectory, followLinks = false)
    fixturesRoot.resolve(fixtureName)
        .copyToRecursively(projectDirectory, followLinks = false,
            overwrite = true) // patches the common fixture
}

Настраиваемое действие копирования

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

sourceRoot.copyToRecursively(destinationRoot, followLinks = false) { source, target ->
    if (source.name.startsWith(".")) {
        CopyActionResult.SKIP_SUBTREE
    } else {
        source.copyToIgnoringExistingDirectory(target, followLinks = false)
        CopyActionResult.CONTINUE
    }
}

Дополнительную информацию об этих расширяющих функциях см. в нашей справке по API.

Расширяющие функции для Java Optional

Расширяющие функции, представленные в Kotlin 1.7.0, теперь стабильны. Эти функции упрощают работу с классами Optional в Java. Они могут быть использованы для распаковки и преобразования Optional объектов на JVM и для более лаконичной работы с Java API. Дополнительную информацию см. в Что нового в Kotlin 1.7.0.

Улучшенная производительность kotlin-reflect

Используя тот факт, что kotlin-reflect теперь компилируется с целевой JVM 1.8, мы мигрировали нашу внутреннюю механизм кэширования на Java ClassValue. Ранее мы кэшировали только KClass, но теперь мы также кэшируем KType и KDeclarationContainer. Эти изменения привели к значительному улучшению производительности при вызове typeOf().

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

Документация Kotlin претерпела ряд заметных изменений:

Переработанные и новые страницы

  • Обзор Gradle – узнайте, как настроить и собрать проект Kotlin с помощью Gradle, доступные опции компилятора, компиляция и кэширование в плагине Kotlin Gradle.

  • Использование nullable-типов в Java и Kotlin – рассмотрите различия между подходами Java и Kotlin к обработке переменных, которые могут быть null.

  • Руководство по Lincheck – узнайте, как настроить и использовать фреймворк Lincheck для тестирования конкурирующих алгоритмов на JVM.

Новые и обновлённые учебники

  • Начало работы с Gradle и Kotlin/JVM – создание консольного приложения с помощью IntelliJ IDEA и Gradle.

  • Создание кроссплатформенного приложения с использованием Ktor и SQLDelight – создание мобильного приложения для iOS и Android с помощью Kotlin Multiplatform Mobile.

  • Начало работы с Kotlin Multiplatform Mobile – изучите кроссплатформенную разработку мобильных приложений с помощью Kotlin и создайте приложение, работающее как на Android, так и на iOS.

END_OF_DOCUMENT_MARKER

Установка Kotlin 1.8.0

IntelliJ IDEA 2021.3, 2022.1 и 2022.2 автоматически предложат обновить плагин Kotlin до версии 1.8.0. IntelliJ IDEA 2022.3 будет поставлять версию плагина Kotlin 1.8.0 в рамках предстоящего незначительного обновления.

Для миграции существующих проектов в Kotlin 1.8.0 в IntelliJ IDEA 2022.3 измените версию Kotlin на 1.8.0 и повторно импортируйте свой проект Gradle или Maven.

Для Android Studio Electric Eel (221) и Flamingo (222) версия 1.8.0 плагина Kotlin будет включена в предстоящих обновлениях Android Studio. Новый компилятор командной строки доступен для скачивания на странице выпуска GitHub.

Руководство по совместимости для Kotlin 1.8.0

Kotlin 1.8.0 — это релиз новых функций и, следовательно, может вносить изменения, которые несовместимы с вашим кодом, написанным для более ранних версий языка. Подробный список этих изменений см. в Руководстве по совместимости для Kotlin 1.8.0.

Последнее изменение: 10 июля 2023
Что нового в Kotlin 1.7.20

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

Spec-Zone.ru

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