Releases

Вышел Kotlin 1.5.0-RC: изменения в стандартной и тестовой библиотеках

Read this post in other languages:
English, Français, 日本語, 한국어, Deutsch, Português do Brasil, Español, 简体中文

Представляем Kotlin 1.5.0-RC — релиз-кандидат, куда вошли все функции, запланированные в версии 1.5.0. Попробуйте все возможности, которые появятся в предстоящем релизе! Сейчас мы дорабатываем новые возможности языка, обновления стандартной библиотеки, улучшенную тестовую библиотеку и другие изменения. До выхода нового релиза мы не будем больше вносить никаких изменений, кроме исправления ошибок.

Попробуйте последние API Kotlin на реальных проектах с версией 1.5.0-RC и помогите нам улучшить официальную версию! Обо всех проблемах сообщайте нам в трекере YouTrack.

Установить 1.5.0-RC

В этой статье мы расскажем об изменениях, появившихся в стандартной и тестовой библиотеках Kotlin в версии 1.5.0-RC:

Подробнее читайте ниже.

Стабильные целочисленные типы без знака

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

  • типы целых чисел без знака: UInt, ULong, UByte, UShort и связанные с ними функции, например, преобразования;
  • агрегированные типы — массивы, диапазоны и прогрессии целых чисел без знака: UIntArray, UIntRange и похожие контейнеры для других типов.

Целочисленные типы без знака появились в режиме беты в Kotlin 1.3. Теперь целые числа без знака и операции с ними стали стабильными, поэтому они будут доступны всем пользователям по умолчанию, и их можно спокойно использовать в реальных проектах.

Новые стабильные API:

  • целочисленные типы без знака;
  • диапазоны и прогрессии целочисленных типов без знака;
  • функции, которые оперируют целочисленными типами без знака.

Массивы целых чисел без знака сохраняют статус бета-версии. То же самое касается varargs целых чисел без знака, которые опираются на массивы. Если вы хотите использовать их в своем коде, включите их с помощью аннотации @ExperimentalUnsignedTypes.

Подробнее о целых числах без знака в Kotlin.

Расширения для API java.nio.file.Path

В новой версии Kotlin появился способ идиоматического использования современного неблокирующего ввода/вывода Java из коробки с помощью функций расширения для java.nio.file.Path.

Вот небольшой пример:

Эти расширения появились в Kotlin 1.4.20 в качестве экспериментальной функциональности, а теперь доступны всем пользователям. Список всех функций, которые можно использовать, см. в пакете kotlin.io.path.

Существующие расширения File API по-прежнему доступны, так что вы сами можете выбрать для себя более удобный API.

Не зависящий от локали API для изменения регистра

Многие из вас знакомы с функциями стандартной библиотеки для изменения регистра строк и символов: toUpperCase(), toLowerCase(), toTitleCase(). Обычно они работают нормально, но могут создавать проблемы при использовании на платформах с разными локалями. Все эти функции учитывают локаль, поэтому в зависимости от нее результат может меняться. Например, какое значение вернет ”Kotlin”.toUpperCase()? Вы скажете: «Разумеется, KOTLIN». Однако в турецкой локали строчная i превращается в прописную İ, и результат будет иным: KOTLİN.

Поэтому мы создали новый API для изменения регистра строк и символов, который не зависит от локали: расширения uppercase(), lowercase(), titlecase() и их аналоги для символов *Char(). Попробовать экспериментальную версию этого API можно было уже в версии 1.4.30.

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

На JVM можно выполнить изменение регистра с учетом локали. Для этого вызовите функции, используя текущую локаль в качестве аргумента:

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

Понятные преобразования Char-to-code и Char-to-digit

Операция получения кода символа в кодировке UTF-16 с помощью функции toInt() часто вызывала трудности. Внешне она очень похожа на функцию String.toInt() для числовых строк из одного знака, которая возвращает значение Int этого числа.

Кроме того, не было общей функции, которая возвращала бы числовое значение 4 для Char '4'.

Для решения этих проблем мы создали новый набор функций преобразования символов в целочисленные коды и числовые значения:

  • Char(code) и Char.code выполняют преобразование из кода в символ и обратно;
  • Char.digitToInt(radix: Int) и его версия *OrNull возвращают целочисленное значение цифры в указанной системе счисления;
  • Int.digitToChar(radix: Int) создает символ из цифры, представляющей собой целое число в системе счисления с указанным основанием.

У этих функций понятные имена, поэтому код удобнее читать:

Новые функции были доступны в экспериментальном виде уже в Kotlin 1.4.30, а теперь мы делаем их стабильными. Поддержка старых функций преобразования символа в число (Char.toInt() и схожие функции для других числовых типов) и числа в символ (Long.toChar() и схожие функции, кроме Int.toChar()) прекращается.

Расширенный мультиплатформенный API символов

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

В новой версии некоторые функции Char становятся доступными на всех платформах и в общем коде. Это:

  • Char.isDigit(), Char.isLetter(), Char.isLetterOrDigit(), которые проверяют, является ли символ буквой или цифрой;
  • Char.isLowerCase(), Char.isUpperCase(), Char.isTitleCase(), которые проверяют регистр символа;
  • Char.isDefined(), которая проверяет, отличается ли общая категория Unicode указанного символа от Cn (undefined);
  • Char.isISOControl(), которая проверяет, является ли символ управляющим символом ISO с кодом в диапазоне \u0000..\u001F или \u007F..\u009F.

Свойство Char.category и его возвращаемый класс перечисления CharCategory, который указывает общую категорию символа в Unicode, теперь доступны в мультиплатформенных проектах.

Строгие версии String?.toBoolean()

Функция Kotlin String?.toBoolean() широко используется для создания логических значений из строк. Она работает очень просто: возвращает значение true для строки “true” независимо от регистра и false для всех остальных строк, включая null.

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

Избежать этого помогут новые строгие версии String?.toBoolean(), которые учитывают регистр:

  • String.toBooleanStrict() выдает исключение для всех входных данных, кроме литералов “true” и “false”;
  • String.toBooleanStrictOrNull() возвращает null для всех входных данных, кроме литералов “true” и “false”.

Изменения в API класса Duration

Экспериментальный API продолжительности и измерения времени появился в стандартной библиотеке в версии 1.3.50. Он обеспечивает точное измерение промежутков времени.

Один из основных классов этого API — Duration. Он представляет собой промежуток между двумя моментами времени. В версии 1.5.0 класс Duration был значительно изменен. Это коснулось и API, и внутреннего представления.

Теперь Duration использует для внутреннего представления значение Long, а не Double. Диапазон значений Long позволяет представить более ста лет с точностью до наносекунды или сто миллионов лет с точностью до миллисекунды. Однако поддерживавшиеся ранее промежутки времени менее наносекунды теперь недоступны.

Кроме того, мы ввели новые свойства для получения продолжительности в виде значения Long. Они доступны для различных единиц времени: Duration.inWholeMinutes, Duration.inWholeSeconds и т. п. Эти функции заменят свойства, использующие значения Double, такие как Duration.inMinutes.

Еще одно изменение — это появление набора новых фабричных функций для создания экземпляров Duration из целочисленных значений. Они определены прямо в типе Duration и заменяют прежние свойства-расширения числовых типов, такие как Int.seconds.

Поскольку были внесены такие значительные изменения, API продолжительности и измерения времени в версии 1.5.0 останется экспериментальным. Включить его можно с помощью аннотации @ExperimentalTime.

Попробуйте новую версию и оставьте отзыв в трекере YouTrack.

Математические операции: целочисленное деление и оператор mod

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

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

В версии 1.5.0-RC мы добавили функцию floorDiv(), которая выполняет целочисленное деление для целых чисел.

В версии 1.5.0 мы вводим новую функцию mod(). Теперь она работает в точном соответствии со своим именем, возвращая остаток, получившийся при целочисленном делении.

Эта функция Kotlin отличается от rem() (или оператора %). Остаток представляет собой разницу между a и a.floorDiv(b) * b. Ненулевой остаток всегда имеет тот же знак, что и b, а a % b может иметь другой знак. Это может быть полезно, например, при создании циклических списков:

Коллекции: firstNotNullOf() и firstNotNullOfOrNull()

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

Например, чтобы получить первый отличный от null результат применения функции-селектора к элементам коллекции, можно вызвать mapNotNull() и first(). В версии 1.5.0 для этого достаточно вызвать одну новую функцию firstNotNullOf(). Вместе с firstNotNullOf() появился и ее аналог *orNull(), который выдает null, если нет возвращаемых значений.

Вот пример возможного сокращения кода.

Представим, что у вас есть класс со свойством, допускающим значение null, и вам нужно первое отличное от null значение свойства из списка экземпляров класса.

Для этого можно перебрать коллекцию и проверить, имеет ли свойство отличное от null значение:

Вместо этого можно использовать существовавшие ранее функции mapNotNull() и firstOrNull(). Обратите внимание: функция mapNotNull() создает промежуточную коллекцию, а для этого требуется дополнительная память, особенно если коллекция большая. В результате может потребоваться преобразование в последовательность.

А вот как это выглядит при использовании новой функции:

Изменения в тестовой библиотеке

В нескольких предыдущих релизах мы не делали крупных обновлений тестовой библиотеки Kotlin kotlin-test, но в этой версии появится ряд долгожданных изменений. В 1.5.0-RC можно попробовать несколько новых функций:

  • единая зависимость kotlin-test в мультиплатформенных проектах;
  • автоматический выбор фреймворка для тестирования исходных наборов Kotlin/JVM;
  • изменения функций утверждения.

Зависимость kotlin-test в мультиплатформенных проектах

Мы продолжаем разрабатывать процесс конфигурирования мультиплатформенных проектов. В версии 1.5.0 мы упростили настройку зависимости kotlin-test для всех исходных наборов.

Теперь вам нужно добавить только одну зависимость kotlin-test в общем тестовом исходном наборе. Плагин Gradle сам определит соответствующие платформенные зависимости для других исходных наборов:

  • kotlin-test-junit для исходных наборов JVM. Кроме того, вы можете переключиться на kotlin-test-junit-5 или kotlin-test-testng, если явно включите их (читайте ниже, как это сделать);
  • kotlin-test-js для исходных наборов Kotlin/JS;
  • kotlin-test-common и kotlin-test-annotations-common для общих исходных наборов;
  • отдельных артефактов для исходных наборов Kotlin/Native нет, потому что Kotlin/Native содержит встроенную реализацию API kotlin-test.

Автоматический выбор фреймворка для тестирования исходных наборов Kotlin/JVM

После того, как вы указали зависимость kotlin-test в общем тестовом исходном наборе, как описано выше, исходные наборы JVM автоматически получают ее на JUnit 4. Готово! Сразу после этого можно писать и запускать тесты.

Вот как это выглядит в Groovy DSL:

А вот так — в Kotlin DSL:

Кроме того, можно переключиться на JUnit 5 или TestNG, вызвав в тестовой задаче функцию useJUnitPlatform() или useTestNG().

В проектах с использованием только JVM все работает точно так же, если вы добавили зависимость kotlin-test.

Изменения функций утверждения

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

Сначала вкратце рассмотрим новые функции:

  • assertIs<T>() и assertIsNot<T>() проверяют тип значения;
  • assertContentEquals() сравнивает содержимое контейнеров: массивов, последовательностей и любых Iterable. Говоря точнее, эта функция проверяет, содержат ли expected и actual одни и те же элементы в том же порядке;
  • assertEquals() и assertNotEquals() для Double и Float получили новые перегрузки с третьим параметром — точностью;
  • assertContains() проверяет наличие элемента в любом объекте, для которого определен оператор contains(): массив, список, диапазон и т. п.

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

Что касается существующих функций утверждения, теперь можно вызвать останавливаемые функции внутри лямбды, переданной в assertTrue(), assertFalse() и expect(), поскольку теперь это встроенные функции.

Попробуйте все возможности Kotlin 1.5.0

Версия 1.5.0-RC позволяет использовать все современные API языка Kotlin в реальных проектах.

В IntelliJ IDEA или Android Studio нужно установить плагин Kotlin 1.5.0-RC. Посмотрите, как получить версию плагина для раннего доступа.

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

Установить 1.5.0-RC

Как всегда, с новой версией можно поработать онлайн в песочнице Kotlin Playground.

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

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

Примечания к версии Release Candidate

Теперь, когда версия Kotlin 1.5.0 достигла этапа «релиз-кандидат», самое время заняться компиляцией и публикацией. В отличие от предыдущих предрелизных версий, двоичные файлы, созданные в Kotlin 1.5.0-RC, будут гарантированно совместимы с Kotlin 1.5.0.

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

Как всегда, мы очень ждем ваших отзывов. Обо всех проблемах вы можете сообщить нам в трекере YouTrack. Сделаем Kotlin 1.5.0 лучше для всего сообщества!

Установить 1.5.0-RC

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

Discover more