Releases

Вышел Kotlin 1.6.0

Read this post in other languages:
English, Français, 한국어, Deutsch, 简体中文

Мы выпустили новую версию Kotlin 1.6.0, где были стабилизированы исчерпывающие выражения when, а также добавлен плагин Kover и новый менеджер памяти Kotlin/Native. Другие возможности языка и стандартной библиотеки, появившиеся в версии 1.5.30, также стабилизированы. Мы благодарны всем, кто прислал свои отзывы, комментарии и предложения. Если вы еще не попробовали новые функции, сделайте это сейчас!

В этой статье мы расскажем о следующих обновлениях:

  • функции языка: sealed-выражения when (when statement), останавливаемые функции и преобразования suspend, создание объектов классов аннотаций, улучшенный вывод обычных типов и вывод типов построителей;
  • Kotlin/JVM: оптимизация делегированных свойств и повторяемые аннотации;
  • Kotlin/Native: превью новой модели управления памятью, поддержка Xcode 13, кросс-компиляция проектов с целевой платформой Windows, обновления LLVM и компоновщика, улучшения производительности и унифицированный ABI плагинов компилятора;
  • возможность отключения скачивания Node.js и Yarn для Kotlin/JS;
  • анонс Kover;
  • стандартная библиотека: новые функции стандартного ввода, стабилизация typeOf() и API Duration, а также других функций stdlib.

Подпишитесь на наш блог, чтобы не пропустить информацию об обновлениях Kotlin

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

Если вы пользуетесь IntelliJ IDEA или Android Studio, то сможете автоматически обновиться до новой версии Kotlin, как только она будет доступна в них.

Подробнее об установке Kotlin 1.6.0.

Установить Kotlin 1.6.0

Возможности языка

Опираясь на ваши отзывы, мы стабилизировали функции, появившиеся в Kotlin 1.5.30.

Sealed (исчерпывающие) выражения when

Пользователи давно ждали появления sealed-выражений (statement) when, когда компилятор Kotlin предупреждает, если выражение when не является исчерпывающим. В результате код становится безопаснее, и вам не нужно вводить собственные функции. 

Kotlin всегда выполнял исчерпывающие проверки выражений (expression) when для sealed-классов, перечислений и логических типов. Это удобно при использовании алгебраических типов данных для моделирования предметной области. Например, у вас могут быть различные предпочтительные контактные данные для пользователей приложения, смоделированные как иерархия sealed-классов:

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

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

Однако до выхода Kotlin 1.6 код, использующий выражения when, успешно компилировался, хотя он не обрабатывал отправку уведомлений пользователям посредством мгновенных сообщений:

Выполнялась только слабая инспекция в IDE, сообщения от компилятора отсутствовали. Начиная с версии Kotlin 1.6, компилятор выдает следующее предупреждение:

Non-exhaustive 'when' statements on sealed class/interface will be prohibited in 1.7. Add an 'is InstantMessage' branch or 'else' branch instead.

В Kotlin 1.7 это станет ошибкой, поэтому случайно забыть об этом уже не получится. Подробнее об этом изменении и его последствиях можно узнать в тикете KT-47709

Останавливаемые функции как супертипы

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

При создании API Kotlin обычно используют функциональные типы, если нужно настроить поведение различных функций библиотек. Например, в интерфейсе Job в API kotlinx.coroutines есть функция-член класса, которая выглядит примерно так:

Ее удобно использовать с такими лямбдами, как invokeOnCompletion { doSomething() }. Если у вас есть класс, который вы хотите использовать для обработки завершения выполнения, можно упростить и оптимизировать код, реализовав функциональный тип () -> Unit прямо в классе, не создавая дополнительную лямбду:

Начиная с Kotlin 1.6, такая оптимизация возможна и с останавливаемыми функциями. Допустим, ваши API принимают останавливаемые функциональные типы, например:

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

Преобразование в останавливаемые типы

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

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

Вместо этого можно вставить в вызов collect ссылку на функцию processItem и получить тот же результат:

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

В Kotlin 1.6 приведенный выше код успешно компилируется и работает.

Улучшенный вывод для рекурсивных универсальных типов

Начиная с версии 1.6.0, компилятор Kotlin может вывести аргумент типа, опираясь только на верхние границы диапазона соответствующего параметра типа, являющегося по умолчанию рекурсивным универсальным типом. Благодаря этому можно создавать разнообразные шаблоны с рекурсивными универсальными типами, которые часто используются в Java для API билдеров.

Улучшения вывода типов построителя

В Kotlin 1.5.30 появился параметр компилятора -Xunrestricted-builder-inference, с помощью которого можно было получать информацию о вызове построителя изнутри лямбд построителя. В частности, это позволило совершать вызовы, возвращающие экземпляр еще не выведенного типа, такого как get() внутри лямбды buildList().

Начиная с версии 1.6.0 больше не нужно указывать -Xunrestricted-builder-inference, чтобы совершать запрещенные прежде вызовы. Параметр компилятора -Xenable-builder-inference позволяет также писать собственные универсальные построители, не применяя аннотацию @BuilderInference и автоматически включать вывод типов построителя, если вывод обычных типов не позволяет вычислить информацию типа.

Более длительная поддержка прежних версий API

Начиная с версии 1.6.0, можно вести разработку с использованием не двух, а трех прежних версий API (помимо текущей стабильной версии). В настоящий момент это API версий 1.3, 1.4, 1.5 и 1.6.

Kotlin/JVM

Повторяемые аннотации с временем хранения RUNTIME. В Kotlin, как и в Java 8, есть повторяемые аннотации. В Kotlin 1.6 эта функциональность стала совместима с Java, а @kotlin.annotation.Repeatable теперь принимает любое значение времени хранения и делает аннотацию повторяемой и в Kotlin, и в Java. Кроме того, теперь повторяемые аннотации Java поддерживаются и в Kotlin.

Kotlin/Native

Мы выпустили экспериментальную версию нового менеджера памяти Kotlin/Native. С появлением этой функциональности мы сделали еще один шаг к единообразию разработки в мультиплатформенных проектах. Новый менеджер памяти устраняет существующие ограничения на совместное использование объектов в разных потоках и предлагает параллельные программные примитивы, которые полностью защищены от утечек памяти, безопасны и не требуют специального управления или аннотаций со стороны разработчиков.

Вы можете спокойно обновить Xcode и продолжать работу над проектами Kotlin, поскольку новая версия Kotlin/Native поддерживает Xcode 13

Компиляция проектов Windows на любом хосте. Проекты Windows mingwX64 и mingwX86 можно компилировать на любом хосте, поддерживающем Kotlin/Native.

Мы переработали зависимость LLVM, используемую внутри Kotlin/Native. Это дало ряд преимуществ, позволило обновить версию LLVM до 11.1.0 и уменьшить размер зависимости.

Унификация ABI плагинов компилятора с бэкендами JVM и JS IR. Теперь плагин Kotlin Multiplatform Gradle может использовать для Kotlin/Native тот же встраиваемый jar-файл компилятора, что и для бэкендов JVM и JS IR. Благодаря этому для Native и других поддерживаемых платформ можно использовать одни и те же артефакты плагинов компилятора.

Kotlin/JS

При сборке проекта на сервере без подключения к интернету теперь можно отключить скачивание Node.js и Yarn для проектов Kotlin/JS и использовать уже установленные на хосте экземпляры.

Kover

Проблема точного определения покрытия кода существует еще с самого первого релиза. Код Kotlin поддерживают несколько отличных инструментов, например JaCoCo, но они не интегрированы полностью в наш тулчейн и мультиплатформенные проекты. В новой версии Kotlin мы подошли к решению этой проблемы. Представляем Kover — новый плагин Gradle, который оценивает покрытие кода Kotlin, собранного компилятором Kotlin/JVM. Он пока находится на ранней стадии разработки и имеет статус экспериментальной функциональности. Мы будем благодарны вам за отзывы об этом инструменте, оставленные в GitHub.

Подробнее о Kover можно узнать, посмотрев это видео.

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

В Kotlin 1.6.0 мы выполнили три пункта официального плана развития стандартной библиотеки: избавились от !! после readLine(), стабилизировали typeOf() и обеспечили стабильный API Duration. Кроме того, были стабилизированы следующие функции stdlib:

  • построители коллекций;
  • побитовые операции отражения с целыми числами;
  • функция Regex для разделения строкового значения и создания последовательности.

Кроме того, мы добавили возможность вызова compareTo в инфиксной нотации и обеспечили одинаковое поведение функций replace() в JVM и JS.

Новые функции для стандартного ввода

В Kotlin 1.6.0 больше не нужно использовать оператор проверки ненулевого значения !! после считывания строки стандартного ввода. Это упрощает изучение Kotlin и делает работу удобнее для новичков.

Мы добавили новые функции для чтения с консоли, которые работают следующим образом:

  • readln() выдает исключение при достижении конца файла. Эту функцию следует использовать вместо проверки результата readLine() на значение null с помощью оператора !!.
  • Новая функция readlnOrNull() — альтернативный вариант, возвращающий значение null. Она работает так же, как прежняя функция readLine(), но у нее более очевидное имя.

В настоящий момент эти функции доступны для JVM и Native. Правила именования этих функций соответствуют их аналогу println(), что особенно важно для новичков.

Стабильный API Duration

Благодаря вашим отзывам нам удалось стабилизировать API Duration и выполнить соответствующий пункт плана развития.

Помимо более понятных правил выполнения Duration.toString() и новых функций вычленения объектов Duration из строк, которые появились в режиме предпросмотра в версии 1.5.30, в API Duration были сделаны следующие изменения:

  • В компонент days функции toComponents был добавлен тип Long вместо Int, чтобы значения не обрезались.
  • Перечисление DurationUnit больше не является псевдонимом типа. В JVM отсутствуют случаи его использования в качестве псевдонима для java.util.concurrent.TimeUnit.
  • В соответствии с пожеланиями сообщества мы вернули свойства расширения, такие как Int.seconds. Для ограничения возможностей их использования они доступны только в компаньоне класса Duration.

Стабильная функция typeOf()

В Kotlin 1.6.0 стабилизирована функция typeOf(). Тем самым мы выполнили соответствующий пункт плана развития. Начиная с версии 1.3.40, typeOf() была доступна на платформе JVM в качестве экспериментального API. Теперь ее можно использовать на любой платформе Kotlin и получить представление KType для любого типа Kotlin, выводимого компилятором. 

Стабильные построители коллекций

В Kotlin 1.6.0 стабилизированы функции построителей коллекций: buildMap(), buildList() и buildSet(). Возвращаемые построителями коллекции теперь сериализуются в состоянии только для чтения.

Стабильные побитовые операции отражения с целыми числами

В Kotlin 1.6.0 стабилизированы функции rotateLeft() и rotateRight(), которые отражают двоичное представление числа влево или вправо на указанное число битов.

Стабильная функция Regex для разделения строкового значения и создания последовательности

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

compareTo в инфиксной нотации

Мы добавили возможность вызова функции Comparable.compareTo в инфиксной нотации для сравнения порядка двух объектов: 

Последовательное поведение replace() и replaceFirst() в JVM и JS

До выхода Kotlin 1.6.0, функции replace() и replaceFirst() для регулярных выражений по-разному вели себя в JVM и JS, если заменяющая строка содержала ссылку на группу. Теперь их поведение в Kotlin/JS совпадает с поведением в JVM.

​​Совместимость

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

Как установить Kotlin 1.6.0

Если вы уже пользуетесь IntelliJ IDEA или Android Studio, IDE автоматически предложит вам обновиться до версии 1.6.0. Также можно обновить версию вручную — следуйте этой инструкции.

Для полной поддержки Kotlin вы всегда можете скачать свежие версии этих IDE:

  • IntelliJ IDEA — разработка приложений на Kotlin для разных платформ;
  • Android Studio — разработка приложений под Android и кросс-платформенных мобильных приложений.

Также проверьте, что вы обновили библиотеки kotlinx до совместимых версий и указали версию Kotlin 1.6.0 в билд-скриптах ваших проектов.

Скачать компилятор для командной строки можно с GitHub-страницы релиза.

Что делать, если вы столкнулись с проблемами?

  • Обратитесь за помощью в канале в Slack (воспользуйтесь этим приглашением).
  • Сообщите о проблеме в нашем баг-трекере YouTrack.

Следите за новостями о новых возможностях Kotlin! Чтобы подписаться на рассылку об обновлениях языка, заполните форму справа от статьи.

Что еще можно почитать и посмотреть

Кто прислал больше всего сообщений о пробемах 

Ryan Nett (48 тикетов), Zac Sweers (22 тикета), Tianyu Geng (18 тикетов), zhelenskiy (18 тикетов), Thodoris Sotiropoulos (15 тикетов), AndroidDeveloperLB (14 тикетов), Morgan, Bartholomew (14 тикетов), Mikhail Naftal (14 тикетов), Louis CAD (12 тикетов), Philip Wedemann (12 тикетов), Victor Turansky (11 тикетов), Igor Wojda (11 тикетов), Martin Bonnin (11 тикетов), Iaroslav Postovalov (11 тикетов), Cedric (10 тикетов), (9 тикетов), Ben Woodworth (8 тикетов), Tianyi Guan (8 тикетов), Chris Povirk (8 тикетов), Alon Albert (8 тикетов).

Внешние контрибьюторы

Мы хотим поблагодарить всех контрибьюторов, чьи пул-реквесты включены в этот релиз: Pyos, Tianyu Geng, Jinseong Jeon, Steven Schäfer, Mark Punzalan, Hung Nguyen, Mads Ager, Ting-Yuan Huang, Matthew Gharrity, Ivan Gavrilovic, Xin Wang, ov7a, Jiaxiang Chen, Yigit Boyar, Bingran, bracadabra, Steffi Stumpos, Andrey Kuleshov.

Ваша команда Kotlin
The Drive to Develop

Автор оригинальной статьи:

Oksana Mandryka

Alina Grebenkina

Discover more