Releases

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

Представляем 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

Releases

Kotlin 1.5.0-RC 출시: 표준 및 테스트 라이브러리 변경 사항

Kotlin 1.5.0-RC는 1.5.0에 계획된 모든 기능과 함께 사용할 수 있습니다. 향후 릴리스의 전체 내용을 확인하세요! 새로운 언어 기능, stdlib 업데이트, 향상된 테스트 라이브러리 등 다양한 변경 사항이 마무리 단계에 있습니다. 마지막으로 수정 사항만 더해지면 출시 준비가 끝납니다.

1.5.0-RC를 활용해 실제 프로젝트에서 최신 Kotlin API를 사용해 보고 릴리스 버전을 개선할 수 있도록 피드백을 보내주세요! 발견한 모든 문제는 이슈 트래커 YouTrack에 보고해 주세요.

1.5.0-RC 설치

이 게시물에서는 1.5.0-RC의 Kotlin 표준 및 테스트 라이브러리 변경 사항을 안내합니다.

이어서 각각에 대한 자세한 내용을 알아보세요!

안정적인 부호 없는 정수 유형

표준 라이브러리에는 음수가 아닌 정수 연산을 처리하는 데 유용한 부호 없는 정수 API가 포함되어 있습니다. 이 버전에는 다음의 기능이 포함되어 있습니다:

  • 부호 없는 숫자 유형: UInt, ULong, UByte, UShort 및 관련 함수(예: 변환).
  • 집계 유형: 부호 없는 정수의 배열, 범위 및 진행: UIntArray, UIntRange 및 기타 유형에 대한 유사 컨테이너.

부호 없는 정수 유형은 Kotlin 1.3 이후 베타에서 사용할 수 있었습니다. 이제 부호 없는 정수 유형과 연산을 안정적인 것으로 분류하여 별도의 선택 과정 없이 실제 프로젝트에서 안전하게 사용할 수 있습니다.

새로 도입된 안정적 API는 다음과 같습니다.

  • 부호 없는 정수 유형
  • 부호 없는 정수 유형의 범위와 진행
  • 부호 없는 정수 유형으로 작동하는 함수

부호 없는 정수의 배열은 베타 버전에서 유지됩니다. 배열이 기본적으로 지원되는 부호 없는 정수 varargs도 마찬가지입니다. 코드에서 이 부분을 사용하려면 @ExperimentalUnsignedTypes 어노테이션을 넣어야 합니다.

Kotlin에서 부호 없는 정수에 대해 자세히 알아보세요.

java.nio.file.Path API용 확장 기능

Kotlin은 이제 java.nio.file.Path의 확장 함수를 통해 Kotlin 관용 스타일에서 최신의 블록되지 않은 Java IO를 즉시 사용할 수 있는 방법을 제공합니다.

다음은 간단한 예입니다.

이러한 확장 기능은 Kotlin 1.4.20에서 실험적 기능으로 도입되었으며, 이제 별도의 선택 없이 사용할 수 있습니다. 사용할 수 있는 함수 목록은 kotlin.io.path 패키지를 확인하세요.

File API의 기존 확장 기능은 계속 사용할 수 있으므로 즐겨 이용하는 API를 자유롭게 선택할 수 있습니다.

대소문자 구분 없이 로케일에 구애받지 않는 API

문자열과 문자의 대소문자를 변경하기 위한 다음 stdlib 함수는 많은 분들께 익숙할 것입니다: toUpperCase(), toLowerCase(), toTitleCase() 이러한 함수는 일반적으로 잘 작동하지만 처리하는 플랫폼 로케일에 따라 골치아픈 문제를 일으킬 수 있습니다. 모두 로케일에 민감하여 로케일에 따라 결과가 다를 수 있기 때문입니다. 예를 들어, ”Kotlin”.toUpperCase()로 어떤 결과가 반환될까요? 여러분은 “물론 KOTLIN이죠”라고 말할 것입니다. 그러나 터키어 로케일에서 대문자 iİ이므로 KOTLİN이라는 다른 결과가 얻어집니다.

이제 문자열과 문자의 대소문자를 변경하여 로케일의 구애를 받지 않는 새로운 API가 제공됩니다: uppercase(), lowercase(), titlecase() 확장 기능과 이에 대응하는 *Char() 이미 1.4.30의 테스트 버전에서 이 API를 사용해 보았을 수 있습니다.

새로운 함수는 플랫폼 로케일 설정에 관계없이 동일한 방식으로 작동합니다. 이들 함수를 호출하기만 하면 나머지는 stdlib이 알아서 합니다.

새로운 함수는 플랫폼 로케일 설정에 관계없이 동일한 방식으로 작동합니다. 이들 함수를 호출하기만 하면 나머지는 stdlib이 알아서 합니다.

JVM에서 현재 로케일을 인수로 사용하여 새로운 함수를 호출하면 로케일을 구분하는 대소문자 변경을 수행할 수 있습니다.

이전 함수가 새로운 함수로 완전히 대체되어 더 이상 사용되지 않습니다.

명확한 문자-코드 및 문자-숫자 변환

문자의 UTF-16 코드를 가져오는 연산인 toInt() 함수는 한 자리 문자열에서 String.toInt()와 매우 유사하여 자주 실수를 유발하고는 했습니다. 이 경우 이 숫자가 나타내는 Int가 생성되기 때문입니다.

또한 Char '4'에 대해 숫자 값 4를 반환하는 공통 함수도 없었습니다.

이러한 문제를 해결하기 위해 이제 문자와 해당 정수 코드 및 숫자 값 사이에서 변환을 수행하는 새로운 함수 세트가 제공됩니다.

  • Char(code)Char.code는 문자와 해당 코드 사이에서 변환합니다.
  • Char.digitToInt(radix: Int)와 해당 *OrNull 버전은 지정된 기수의 숫자에서 정수를 생성합니다.
  • Int.digitToChar(radix: Int)는 지정된 기수의 정수를 나타내는 숫자에서 문자를 생성합니다.

이러한 함수는 명확한 이름을 가지며 코드를 더 읽기 쉽게 만듭니다.

새로운 함수는 Kotlin 1.4.30부터 테스트 버전 모드로 사용 가능했으며 이제 안정적으로 작동합니다. 문자에서 숫자로 변환(Char.toInt() 및 다른 숫자 유형에 대한 유사한 함수) 및 숫자에서 문자로 변환(Int.toChar()를 제외한 Long.toChar() 및 유사 함수)하기 위한 이전의 함수는 이제 더 이상 사용되지 않습니다.

확장된 멀티플랫폼 Char API

표준 라이브러리의 멀티 플랫폼 부분을 계속 확장하여 멀티 플랫폼 프로젝트의 공통 코드에 이러한 기능이 이용될 수 있도록 하고 있습니다.

이제 모든 플랫폼과 공통 코드에서 사용할 수 있는 여러 Char 함수가 제공됩니다. 이러한 함수는 다음과 같습니다.

  • 문자가 글자 혹은 숫자인지 여부를 확인하는 Char.isDigit(), Char.isLetter(), Char.isLetterOrDigit()
  • 문자의 대소문자를 확인하는 Char.isLowerCase(), Char.isUpperCase(), Char.isTitleCase()
  • 문자에 Cn(undefined)이 아닌 Unicode 일반 카테고리가 있는지 여부를 확인하는 Char.isDefined()
  • 문자가 \u0000..\u001F 또는 \u007F..\u009F 범위의 코드를 가진 ISO 제어 문자인지 여부를 확인하는 Char.isISOControl()

Unicode에 따라 문자의 일반 범주를 나타내는 Char.category 프로퍼티 및 그 반환 유형 열거형 클래스인 CharCategory를 이제 멀티플랫폼 프로젝트에서 사용할 수 있습니다.

String?.toBoolean()의 엄격한 버전

Kotlin의 String?.toBoolean() 함수는 문자열로부터 부울 값을 만드는 데 널리 사용됩니다. 작동은 매우 간단합니다. 대소문자에 관계 없이 문자열 "true"에서 true이고, null을 포함한 다른 모든 문자열에서는 false입니다.

이 동작은 자연스러운 것처럼 보이지만 잠재적으로 잘못된 상황이 간과될 수 있습니다. 이 함수로 무엇을 변환하든 문자열에 예상치 못한 값이 있어도 부울이 반환됩니다.

이러한 실수를 방지하기 위해 대소문자를 구분하는 String?.toBoolean()의 새로운 엄격 한 버전이 제공됩니다.

  • String.toBooleanStrict()는 리터럴 “true” 및 “false”를 제외한 모든 입력에 대해 예외를 던집니다.
  • String.toBooleanStrictOrNull()은 리터럴 “true” 및 “false”를 제외한 모든 입력에 대해 null을 반환합니다.

Duration API 변경 사항

stdlib 버전 1.3.50부터 실험적으로 도입한 Duration and Time Measurement API를 사용할 수 있었습니다. 이를 통해 시간 간격을 정확하게 측정하기 위한 API가 제공됩니다.

이 API의 주요 클래스 중 하나는 Duration입니다. 이 클래스는 두 시점 사이의 시간을 나타냅니다. 1.5.0에서 Duration은 API와 내부 표현 모두에서 상당한 변경이 이루어졌습니다.

Duration은 이제 Double 대신 내부 표현에 Long 값을 사용합니다. Long 값의 범위를 사용하면 나노초 정밀도로 100년 이상을, 밀리초 정밀도로 1억년 이상을 나타낼 수 있습니다. 그러나 이전에 지원되었던 나노초 미만의 기간은 더 이상 사용할 수 없습니다.

또한 기간을 Long 값으로 검색하기 위한 새로운 프로퍼티도 도입될 예정입니다. 이러한 프로퍼티는 Duration.inWholeMinutes, Duration.inWholeSeconds 등 다양한 시간 단위로 사용할 수 있습니다. 이러한 함수는 Duration.inMinutes와 같은 Double 기반 프로퍼티를 대체합니다.

또 다른 변경 사항은 정수 값에서 Duration 인스턴스를 만드는 새로운 팩토리 함수 집합입니다. 이러한 함수는 Duration 유형에서 직접 정의되며 Int.seconds와 같은 숫자 유형의 이전 확장 프로퍼티를 대체합니다.

변경되는 부분이 많은 점을 감안하여 전체 기간 및 시간 측정 API는 1.5.0에서 실험적으로 유지되며 @ExperimentalTime 어노테이션으로 선택을 지정해야 합니다.

새 버전을 사용해보고 이슈 트래커 YouTrack에서 의견을 공유해주세요.

수학 연산: 내림 나누기 및 mod 연산자

Kotlin에서 정수에 대한 나누기 연산자(/)는 나눗셈 결과의 소수 부분을 제거하는 버림 나눗셈을 수행합니다. 모듈식 산술에는 결과를 반내림하여(더 작은 정수로) 음수에 대해 다른 결과를 생성하는 대안인 내림 나눗셈도 있습니다.

이전에는 내림 나눗셈에 다음과 같은 사용자 지정 함수가 필요했습니다.

1.5.0-RC에서는 정수에 대해 내림 나누기를 수행하는 floorDiv() 함수를 제공합니다.

1.5.0에서는 새로운 mod() 함수를 도입했습니다. 이제 이 함수가 이름에서 알 수 있듯이 내림 나누기의 나머지 부분인 나머지를 반환합니다.

이것은 Kotlin의 rem()(또는 % 연산자)와는 다릅니다. 나머지는 aa.floorDiv(b) * b 사이의 차이입니다. 0이 아닌 계수는 항상 b와 같은 부호를 가지며 a % b는 다른 부호를 가질 수 있습니다. 이러한 부분은 예를 들어 순환 목록을 구현할 때 유용할 수 있습니다.

컬렉션: firstNotNullOf() 및 firstNotNullOfOrNull()

Kotlin 컬렉션 API는 기본 제공되는 함수를 이용해 컬렉션에서 널리 사용되는 다양한 작업을 처리합니다. 일반적이지 않은 경우에는 보통 이러한 함수 호출을 결합합니다. 작동은 하지만 항상 가볍게 처리되지는 않으며 오버헤드가 발생할 수 있습니다.

예를 들어, 컬렉션 요소에서 선택자 함수의 첫 번째 null이 아닌 결과를 가져오려면 mapNotNull()first()를 호출할 수 있습니다. 1.5.0에서는 새 함수 firstNotNullOf()의 단일 호출로 이를 수행할 수 있습니다. firstNotNullOf()와 함께, 반환할 값이 없는 경우 null을 생성하는 *orNull() 대응 함수도 추가됩니다.

다음 예는 이를 통해 코드를 어떻게 단축할 수 있는지를 보여줍니다.

nullable 프로퍼티를 가진 클래스가 있고 클래스 인스턴스 목록에서 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 플러그인이 다른 소스 세트에 대한 해당 플랫폼 종속성을 추론합니다.

  • JVM 소스 세트용 kotlin-test-junit. 명시적으로 활성화하는 경우 kotlin-test-junit-5 또는 kotlin-test-testng로 전환할 수도 있습니다. 이어지는 내용에서 방법을 알아보세요.
  • Kotlin/JS 소스 세트용 kotlin-test-js
  • 공통 소스 세트용 kotlin-test-commonkotlin-test-annotations-common.
  • Kotlin/Native는 kotlin-test API의 기본 구현을 제공하므로 Kotlin/Native 소스 세트에 대한 추가 아티팩트가 없습니다.

Kotlin/JVM 소스 세트에 대한 테스트 프레임워크의 자동 선택

위에서 설명한 대로 공통 테스트 소스 세트에서 kotlin-test 종속성을 지정하면 JVM 소스 세트가 JUnit 4에 대한 종속성을 자동으로 수신합니다. 이게 끝입니다. 즉시 테스트를 작성하고 실행할 수 있습니다!

Groovy DSL에서는 다음과 같이 나타납니다.

그리고 Kotlin DSL에서는 다음과 같습니다.

테스트 작업에서 간단히 함수를 호출하여 JUnit 5 또는 TestNG로 전환할 수도 있습니다: useJUnitPlatform() 또는 useTestNG().

kotlin-test 종속성을 추가하면 JVM 전용 프로젝트에서도 동일하게 작동합니다.

어설션 함수 업데이트

1.5.0에서는 기존 어설션 함수를 개선하는 동시에 새로운 어설션 함수도 다수 준비했습니다.

먼저, 새로운 함수를 간단히 살펴 보겠습니다.

  • assertIs<T>()assertIsNot<T>()는 값의 유형을 확인합니다.
  • assertContentEquals()는 배열, 시퀀스 및 모든 Iterable에 대한 컨테이너 내용을 비교합니다. 보다 정확하게는 예상실제가 동일한 순서로 동일한 요소를 포함하는지 확인합니다.
  • DoubleFloat에 대한 assertEquals()assertNotEquals()에는 세 번째 매개변수인 정밀도가 포함된 새로운 오버로드가 있습니다.
  • assertContains()는 배열, 목록, 범위 등 contains() 연산자가 정의된 모든 객체에서 항목의 존재 유무를 확인합니다.

다음은 이러한 함수의 사용법을 보여주는 간단한 예입니다.

기존 어설션 함수와 관련하여 이제 assertTrue(), assertFalse()expect()로 전달된 람다 표현식 내에서 일시 중지 함수를 호출할 수 있습니다. 이러한 함수는 이제 인라인 화되었기 때문입니다.

Kotlin 1.5.0의 모든 기능을 사용해 보세요.

1.5.0-RC를 사용하여 이러한 모든 최신 Kotlin API를 실제 프로젝트에 적용해 보세요!

IntelliJ IDEA 또는 Android Studio에서 Kotlin 플러그인 1.5.0-RC를 설치하세요. EAP 플러그인 버전을 사용하는 방법에 대해서도 알아보세요.

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에서 확인할 수도 있습니다.

릴리스 후보 안내

Kotlin 1.5.0의 릴리스 후보가 결정되었으며 이제 여러분이 컴파일하고 게시할 차례입니다! 기존 주요 릴리스와는 달리 Kotlin 1.5.0-RC에서 생성된 바이너리는 Kotlin 1.5.0과 호환성이 보장됩니다.

의견을 공유해 주세요

이번이 다음 기능 릴리스에 영향을 미칠 수 있는 마지막 기회입니다! 발견한 문제가 있으면 이슈 트래커에서 공유해 주세요. 여러분과 커뮤니티를 위해 Kotlin 1.5.0 개선에 동참해 주세요!

1.5.0-RC 설치


이 게시물은 Pavel Semyonov가 작성한 Kotlin 1.5.0-RC Released: Changes to the Standard and Test Libraries를 번역한 글입니다.

Discover more

Kotlin 1.5.0-RC 版本发布:标准库和测试库的变更

Kotlin 1.5.0-RC 版本已具备 1.5.0 版本计划的所有特性——请查看即将发布版本的全部内容! 新的语言特性,标准库的更新,改进的测试库以及许多正在逐步完善的改动。 在正式版发行之前仅有的改动将是问题修复。

在您的项目中尝试 1.5.0-RC 的现代化 Kotlin API,并帮助我们改善发行版吧! 您可以向我们的问题跟踪器(YouTrack)报告所遇到的任何问题。

安装 1.5.0-RC

在这篇文章中,我们将向您介绍 1.5.0-RC 中 Kotlin 标准库和测试库的变更:

您可以在下面找到所有详细信息!

稳定的无符号整型

标准库中包含了无符号整型 API,可用于处理非负整数运算。包括:

  • 无符号的数字类型: UIntULongUByteUShort,以及相关函数,例如转换。
  • 集合类型:无符号整型的数组,范围和级数: UIntArrayUIntRange,以及其他类型的类似容器。

无符号整型从 Kotlin 1.3 可以使用。 现在,我们将无符号整型和对他们的操作分类为稳定类型,使它们无需声明 opt-in 即可使用,并且可以在实际项目中安全使用。

新的稳定 API 是:

  • 稳定的无符号整型
  • 无符号整型的范围和级数
  • 使用无符号整型进行运算的函数

无符号整型数组仍保留在 Beta 中。 由数组支持的无符号整数 varargs 也是如此。 如果要在代码中使用它们,可以使用 @ExperimentalUnsignedTypes 注解选择加入。

了解更多有关 Kotlin 无符号整型的信息。

Java.nio.file.Path API 的扩展

Kotlin 现在提供了一种通过 non-blocking Java IO 扩展函数以Kotlin 惯用风格调用现代的无阻塞 Java IO 的方法。

这是一个小示例:

这些扩展是在 Kotlin 1.4.20 中作为实验功能引入的,现在无需 opt-in 注解即可使用。 查看 kotlin.io.path 软件包,以获取可以使用的函数列表。

File API 的现有扩展仍然可用,因此你可以自由选择喜欢的API。

与语言环境无关的大写和小写的 API

许多人都熟悉更改字符串和字符大小写的标准库函数: toUpperCase()toLowerCase()toTitleCase() 。 通常它们可以正常工作,但是在处理不同的平台语言环境设置时会让你头痛–它们都对语言环境设置敏感,这意味着它们的结果可能会因语言环境设置而异。 例如,"Kotlin".toUpperCase()返回什么? 你会说:“显然是KOTLIN”。 但是如果你把语言环境设置为土耳其,大写字母iİ,因此结果会有所不同:KOTLİN

现在有一个新的与语言环境无关的 API,用于更改字符串和字符的大小写: uppercase()lowercase()titlecase() 扩展及其对应的 * Char()。 您可能已经在 1.4.30 预览中尝试过了。

无论平台的区域设置如何,新函数的返回结果是相同的。 只需调用这些函数,其余的留给标准库。

无论平台的区域设置如何,新函数的返回结果是相同的。
只需调用这些函数,其余的留给标准库。

在 JVM 上,可以通过使用当前语言环境作为参数调用新函数来执行对语言环境敏感的大小写更改:

新函数将完全取代已经废弃的旧函数。

清除字符到编码值和字符到数字值的转换

获取字符的 UTF-16 编码的操作-toInt()函数-是一个常见的陷阱,因为它看起来非常类似于只有一个数字的字符串的 String.toInt() 操作,该操作产生一个由该字符串表示的 Int

此外,没有通用函数会为Char '4'返回数字值 4

为了解决这些问题,现在提供了一组新函数,用于在字符及数字码和数字值之间进行转换:

  • Char(code)Char.code 在 char 及其数字码之间转换。
  • Char.digitToInt(radix: Int) 和 its *OrNull 从指定基数的字符创建一个整数。
  • Int.digitToChar(radix: Int) 从一个数字创建一个字符,该数字表示指定基数中的整数。

这些函数具有清晰的名称,并使代码更具可读性:

Kotlin 1.4.30 开始预览模式下可用的新函数现已稳定。 字符到数字转换的旧函数( Char.toInt()和其他数字类型的相似函数)和数字到字符转换(Long.toChar()和类似的字符,但Int.toChar()除外)的旧函数现在已经废弃。

Char API的多平台扩展方法

我们将继续扩展标准库的跨平台部分,以将其所有功能提供给跨平台项目的通用代码。
现在我们已经向全平台以及通用代码提供大部分的 Char函数了。 这些函数包括:

  • 检查一个字符是字母还是数字的 Char.isDigit(), Char.isLetter(), Char.isLetterOrDigit()
  • 检查字符大小写的 Char.isLowerCase(), Char.isUpperCase(), Char.isTitleCase()
  • 检查字符是否含有Cn (未定义)以外 Unicode 通用类别Char.isDefined()
  • 检查字符是否为 ISO 控制字符Char.isISOControl(),其字节编码范围为 \u0000..\u001F or \u007F..\u009F

Char.category属性及其返回的枚举类型CharCategory(根据Unicode指示字符的通用类型)现可在跨平台项目访问。

精确版本的 String?.toBoolean()

Kotlin的String?.toBoolean()函数广泛用于通过字符串创建布尔值。 它的工作原理非常简单: 不论大小写,在"true"字符串上都为true,而其他字所有符串(包括null)上都为false

虽然这种表现看起来很自然,但它隐藏了潜在的异常情况。 通过该函数的转换,无论字符串具有哪些非常规的值,你都将得到一个布尔值。

String?.toBoolean() 新的区分大小写的严格版本有助于避免此类错误:

  • String.toBooleanStrict() 会对除“true”和“false”以外的所有输入抛出异常。
  • String.toBooleanStrictOrNull() 会对除“true”和“false”以外的所有输入都返回 null

Duration API 的更改

从1.3.50版开始的实验性持续时间和时间测量API 已在stdlib中提供。 提供了用于精确测量时间间隔的API。

这些API的其中一个关键类是 Duration。 它表示两个时刻之间的时间长度。 在1.5.0,Duration其API和内部形式发生了重大变化。

Duration 其内部现在使用Long值类型代替了DoubleLong值的表示范围相当于纳秒级的一百多年或毫秒级的一亿年。 但是,此前的亚纳秒级持续时间已不再支持。

我们还引入了新的属性值,用于获取durationLong值。 它们可用于各种时间单位:Duration.inWholeMinutesDuration.inWholeSeconds等。 这些函数用来替换基于Double的属性,例如Duration.inMinutes

另一个改动是一组新的工厂函数,用于通过整数创建Duration实例。 它们直接定义在Duration类型中,以替换数字类型的旧扩展属性,例如Int.seconds

由于这些重大更改,所有持续时间和时间测量的API在1.5.0中仍处于试验阶段,需要@ExperimentalTime注释来选择性引入。

请尝试新的版本,并在我们的问题跟踪器 YouTrack 中分享你的反馈。

数学运算: 向下取整和求余运算符

在Kotlin中,整数的除法运算符 (/) 表示截断除法,它去掉了结果的小数部分。 在模运算中,还有另一种选择向下取整除法,其结果将向下取整 (朝较小的整数方向) ,从而对负数会产生不同的结果。

在之前,向下取整除法将要求传递一个自定义函数,如:

在1.5.0-RC,我们引入了codefloorDiv()函数,该函数将对整数进行向下取整运算。floorDiv()函数,该函数将对整数进行向下取整运算。

在1.5.0,我们引入了新的mod()函数。 现在,它的功能完全符合其名称–-它返回模数,即向下取整除法的余数部分。

它不同于Kotlin的rem() (或%运算符) 。 模数是aa.floorDiv(b)* b的差。 非零模数始终与b具有相同的符号,而a%b可以有不同的符号。 例如,在实现循环列表时,这可能会很有用:

集合: firstNotNullOf() and firstNotNullOfOrNull()

Kotlin集合API通过内置函数覆盖了一系列针对集合的流行操作。 对于不常见的案例,通常将这些函数调用结合到一起。 尽管它能完成任务,但通常来说看起来并不优雅,而且可能会导致额外的开销。

例如,要通过选择器函数获取集合的第一个非空结果,可以调用mapNotNull()first()。 在1.5.0,通过新函数firstNotNullOf(),你只需要一次调用便能做到。 我们与firstNotNullOf()一同添加了它对应的*orNull()函数,如果没有返回值,将返null。

以下是代码简洁后的示例。

假设你的类有一个可空属性,同时你需要获取类实例数组中的第一个非空值。

你可以通过迭代集合并检查属性是否为非null来实现:

另一种方式是使用旧函数mapNotNull()firstOrNull()。 请注意, mapNotNull()会创建一个中间集合,尤其是对于大型集合,这会消耗额外的内存。 因此,这里可能需要转换为序列。

这就是新函数看起来的样子:

测试库的变更

我们已有几个正式版没有发布 Kotlin 测试库 kotlin-test的重要更新了,而现在我们提供了一些期待已久的改动。 在1.5.0-RC,你可以尝试许多新特性:

  • 在多平台项目里只需要对codekotlin-testdo单次依赖。>kotlin-test`单次依赖。
  • 自动为Kotlin/JVM源集选择测试框架。
  • 断言函数的更新。

多平台项目中的kotlin-test依赖

我们仍持续多平台项目配置流程的开发。 在1.5.0,我们让所有源集更加易于创建对kotlin-test的依赖。

现在,你仅仅需要在通用测试源集中添加kotlin-test依赖项。 Gradle插件将为其他源集推断出平台对应的依赖:

  • 对于JVM源集则是kotlin-test-junit。 你可以显式指定切换到kotlin-test-junit-5kotlin-test-testng(继续阅读了解具体方法)。
  • 对于 Kotlin/JS 源集则是kotlin-test-js
  • 对于通用源集则是 kotlin-test-commonkotlin-test-annotations-common
  • Kotlin/Native源集没有多余的工件,因为Kotlin/Native提供了kotlin-testAPI的内置实现。

为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>()
  • 用于比较数组、序列以及所有Iterable内容的 assertContentEquals()。 更准确地说,它检查预期和实际的元素及其顺序是否一致。
  • DoubleFloatassertEquals()assertNotEquals()有新的重载,并带有第三个参数–精度。
  • 检查数组、列表、范围等是否contains()指定objectassertContains()

以下是一个简短的示例,展示了这些函数的用法:

对于现有的断言函数——现在可以在assertTrue()assertFalse()lambda参数内调用 suspending functions 了,以及expect(),因为这些函数现在是 内联 的。

尝试 Kotlin 1.5.0的所有特性

让 1.5.0-RC 为您的项目引入现代化的 Kotlin API!

在 IntelliJ IDEA 或 Android Studio 安装 1.5.0-RC 的 Kotlin 插件。 了解如何获取插件的EAP版本

通过 1.5.0-RC 构建现有项目,以检查在 1.5.0 下它们如何工作。 由于预览版本更简易的配置,如有必要,你只需要将Kotlin版本更改为 1.5.0-RC调整依赖版本

安装 1.5.0-RC

一如往常,你可以在 Kotlin Playground 在线尝试最新的版本。

Compatibility

与所有主要版本一样,某些先前宣布的变更的弃用周期将在 Kotlin 1.5.0 版本结束。
所有这些情况都经过了语言委员会的仔细审查,并在 Kotlin 1.5 兼容性指南中列出。
您也可以在 YouTrack 上浏览这些变更。

候选版本说明

Kotlin 1.5 最终候选版本现已推出,是时候开始编译和发布了! 与以前的里程碑版本不同,使用 Kotlin 1.5-RC 创建的二进制文件与 Kotlin 1.5.0 的兼容性可得到充分保证。

分享反馈

这是你能参与影响下一功能版本的最后机会了! 你可以向我们的问题跟踪器(YouTrack)报告所遇到的任何问题。 让Kotlin 1.5.0为了你和社区变得更好!

安装 1.5.0-RC

特别感谢由来自 Kotlin 社区的 Shaowei ChangPye52 为本篇博文提供中文译文。

Discover more

Early Access Program

Kotlin 1.5.0-RC Released: Changes to the Standard and Test Libraries

Kotlin 1.5.0-RC is available with all the features planned for 1.5.0 – check out the entire scope of the upcoming release! New language features, stdlib updates, an improved testing library, and many more changes are receiving a final polish. The only additional changes before the release will be fixes.

Try the modern Kotlin APIs on your real-life projects with 1.5.0-RC and help us make the release version better! Report any issues you find to our issue tracker, YouTrack.

Install 1.5.0-RC

In this post, we’ll walk you through the changes to the Kotlin standard and test libraries in 1.5.0-RC:

You can find all the details below!

Stable unsigned integer types

The standard library includes the unsigned integer API that comes in useful for dealing with non-negative integer operations. It includes:

  • Unsigned number types: UInt, ULong, UByte, UShort, and related functions, such as conversions.
  • Aggregate types: arrays, ranges, and progressions of unsigned integers: UIntArray, UIntRange, and similar containers for other types.

Unsigned integer types have been available in Beta since Kotlin 1.3. Now we are classifying the unsigned integer types and operations as stable, making them available without opt-in and safe to use in real-life projects.

Namely, the new stable APIs are:

  • Unsigned integer types
  • Ranges and progressions of unsigned integer types
  • Functions that operate with unsigned integer types

Arrays of unsigned integers remain in Beta. So do unsigned integer varargs that are backed by arrays. If you want to use them in your code, you can opt-in with the @ExperimentalUnsignedTypes annotation.

Learn more about unsigned integers in Kotlin.

Extensions for java.nio.file.Path API

Kotlin now provides a way to use the modern non-blocking Java IO in a Kotlin-idiomatic style out of the box via the extension functions for java.nio.file.Path.

Here is a small example:

These extensions were introduced as an experimental feature in Kotlin 1.4.20, and are now available without an opt-in. Check out the kotlin.io.path package for the list of functions that you can use.

The existing extensions for File API remain available, so you are free to choose the API you like best.

Locale-agnostic API for uppercase and lowercase

Many of you are familiar with the stdlib functions for changing the case of strings and characters: toUpperCase(), toLowerCase(), toTitleCase(). They generally work fine, but they can cause a headache when it comes to dealing with different platform locales – they are all locale-sensitive, which means their result can differ depending on the locale. For example, what does ”Kotlin”.toUpperCase() return? “Obviously KOTLIN”, you would say. But in the Turkish locale, the capital i is İ, so the result is different: KOTLİN.

Now there is a new locale-agnostic API for changing the case of strings and characters: uppercase(), lowercase(), titlecase() extensions, and their *Char() counterparts. You may have already tried its preview in 1.4.30.

The new functions work the same way regardless of the platform locale settings. Just call these functions and leave the rest to the stdlib.

On the JVM, you can perform locale-sensitive case change by calling the new functions with the current locale as an argument:

The new functions will completely replace the old ones, which we’re deprecating now.

Clear Char-to-code and Char-to-digit conversions

The operation for getting a UTF-16 code of a character – the toInt() function – was a common pitfall because it looks pretty similar to String.toInt() on one-digit strings that produces an Int presented by this digit.

Additionally, there was no common function that would return the numeric value 4 for Char '4'.

To solve these issues, there is now a set of new functions for conversion between characters and their integer codes and numeric values:

  • Char(code) and Char.code convert between a char and its code.
  • Char.digitToInt(radix: Int) and its *OrNull version create an integer from a digit in the specified radix.
  • Int.digitToChar(radix: Int) creates a char from a digit that represents an integer in the specified radix.

These functions have clear names and make the code more readable:

The new functions have been available since Kotlin 1.4.30 in the preview mode and are now stable. The old functions for char-to-number conversion (Char.toInt() and similar functions for other numeric types) and number-to-char conversion (Long.toChar() and similar except for Int.toChar()) are now deprecated.

Extended multiplatform char API

We’re continuing to extend the multiplatform part of the standard library to provide all of its capabilities to the multiplatform project common code.

Now we’ve made a number of Char functions available on all platforms and in common code. These functions are:

  • Char.isDigit(), Char.isLetter(), Char.isLetterOrDigit() that check if a char is a letter or a digit.
  • Char.isLowerCase(), Char.isUpperCase(), Char.isTitleCase() that check the case of a char.
  • Char.isDefined() that checks whether a char has a Unicode general category other than Cn (undefined).
  • Char.isISOControl() that checks whether a char is an ISO control character, that has a code in the ranges \u0000..\u001F or \u007F..\u009F.

The property Char.category and its return type enum class CharCategory, which indicates a character’s general category according to Unicode, are now available in multiplatform projects.

Strict versions of String?.toBoolean()

Kotlin’s String?.toBoolean() function is widely used for creating boolean values from strings. It works pretty simply: it’s true on a string "true" regardless of its case and false on all other strings, including null.

While this behavior seems natural, it can hide potentially erroneous situations. Whatever you convert with this function, you get a boolean even if the string has some unexpected value.

New case-sensitive strict versions of the String?.toBoolean() are here to help avoid such mistakes:

  • String.toBooleanStrict() throws an exception for all inputs except literals “true” and “false”.
  • String.toBooleanStrictOrNull() returns null for all inputs except literals “true” and “false”.

Duration API changes

The experimental duration and time measurement API has been available in the stdlib since version 1.3.50. It offers an API for the precise measurement of time intervals.

One of the key classes of this API is Duration. It represents the amount of time between two time instants. In 1.5.0, Duration receives significant changes both in the API and internal representation.

Duration now uses a Long value for the internal representation instead of Double. The range of Long values enables representing more than a hundred years with nanosecond precision or a hundred million years with millisecond precision. However, the previously supported sub-nanosecond durations are no longer available.

We are also introducing new properties for retrieving a duration as a Long value. They are available for various time units: Duration.inWholeMinutes, Duration.inWholeSeconds, and others. These functions come to replace the Double-based properties such as Duration.inMinutes.

Another change is a set of new factory functions for creating Duration instances from integer values. They are defined directly in the Duration type and replace the old extension properties of numeric types such as Int.seconds.

Given such major changes, the whole duration and time measurement API remains experimental in 1.5.0 and requires an opt-in with the @ExperimentalTime annotation.

Please try the new version and share your feedback in our issue tracker, YouTrack.

Math operations: floored division and the mod operator

In Kotlin, the division operator (/) on integers represents the truncated division, which drops the fractional part of the result. In modular arithmetics, there is also an alternative – floored division that rounds the result down (towards the lesser integer), which produces a different result on negative numbers.

Previously, floored division required a custom function like:

In 1.5.0-RC, we present the floorDiv() function that performs floored division on integers.

In 1.5.0, we’re introducing the new mod() function. It now works exactly as its name suggests – it returns the modulus that is the remainder of the floored division.

It differs from Kotlin’s rem() (or % operator). Modulus is the difference between a and a.floorDiv(b) * b. Non-zero modulus always has the same sign as b while a % b can have a different one. This can be useful, for example, when implementing cyclic lists:

Collections: firstNotNullOf() and firstNotNullOfOrNull()

Kotlin collections API covers a range of popular operations on collections with built-in functions. For cases that aren’t common, you usually combine calls of these functions. It works, but this doesn’t always look very elegant and can cause overhead.

For example, to get the first non-null result of a selector function on the collection elements, you could call mapNotNull() and first(). In 1.5.0, you can do this in a single call of a new function firstNotNullOf(). Together with firstNotNullOf(), we’re adding its *orNull() counterpart that produces null if there is no value to return.

Here is an example of how it can shorten your code.

Assume that you have a class with a nullable property and you need its first non-null value from a list of the class instances.

You can implement this by iterating the collection and checking if a property is not null:

Another way is to use the previously existing functions mapNotNull() and firstOrNull(). Note that mapNotNull() builds an intermediate collection, which requires additional memory, especially for big collections. And so, a transformation to a sequence may be also needed here.

And this is how it looks with the new function:

Test library changes

We haven’t shipped major updates to the Kotlin test library kotlin-test for several releases, but now we’re providing some long-awaited changes. With 1.5.0-RC, you can try a number of new features:

  • Single kotlin-test dependency in multiplatform projects.
  • Automatic choice of a testing framework for Kotlin/JVM source sets.
  • Assertion function updates.

kotlin-test dependency in multiplatform projects

We’re continuing our development of the configuration process for multiplatform projects. In 1.5.0, we’ve made it easier to set up a dependency on kotlin-test for all source sets.

Now the kotlin-test dependency in the common test source set is the only one you need to add. The Gradle plugin will infer the corresponding platform dependency for other source sets:

  • kotlin-test-junit for JVM source sets. You can also switch to kotlin-test-junit-5 or kotlin-test-testng if you enable them explicitly (read on to learn how).
  • kotlin-test-js for Kotlin/JS source sets.
  • kotlin-test-common and kotlin-test-annotations-common for common source sets.
  • No extra artifact for Kotlin/Native source sets because Kotlin/Native provides built-in implementations of the kotlin-test API.

Automatic choice of a testing framework for Kotlin/JVM source sets

Once you specify the kotlin-test dependency in the common test source set as described above, the JVM source sets automatically receive the dependency on JUnit 4. That’s it! You can write and run tests right away!

This is how it looks in the Groovy DSL:

And in the Kotlin DSL it is:

You can also switch to JUnit 5 or TestNG by simply calling a function in the test task: useJUnitPlatform() or useTestNG().

The same works in JVM-only projects when you add the kotlin-test dependency.

Assertion functions updates

For 1.5.0, we’ve prepared a number of new assertion functions along with improvements to existing ones.

First, let’s take a quick look at the new functions:

  • assertIs<T>() and assertIsNot<T>() check the value’s type.
  • assertContentEquals() compares the container content for arrays, sequences, and any Iterable. More precisely, it checks whether expected and actual contain the same elements in the same order.
  • assertEquals() and assertNotEquals() for Double and Float have new overloads with a third parameter – precision.
  • assertContains() checks the presence of an item in any object with the contains() operator defined: array, list, range, and so on.

Here is a brief example that shows the usage of these functions:

Regarding the existing assertion functions – it’s now possible to call suspending functions inside the lambda passed to assertTrue(), assertFalse(), and expect() because these functions are now inline.

Try all the features of Kotlin 1.5.0

Bring all these modern Kotlin APIs to your real-life projects with 1.5.0-RC!

In IntelliJ IDEA or Android Studio, install the Kotlin plugin 1.5.0-RC. Learn how to get the EAP plugin versions.

Build your existing projects with 1.5.0-RC to check how they will work with 1.5.0. With the new simplified configuration for preview releases, you just need to change the Kotlin version to 1.5.0-RC and adjust the dependency versions, if necessary.

Install 1.5.0-RC

As always, you can try the latest version online in the Kotlin Playground.

Compatibility

As with all feature releases, some deprecation cycles of previously announced changes are coming to an end with Kotlin 1.5.0. All of these cases were carefully reviewed by the language committee and are listed in the Compatibility Guide for Kotlin 1.5. You can also explore these changes on YouTrack.

Release candidate notes

Now that we’ve reached the release candidate for Kotlin 1.5.0, it is time for you to start compiling and publishing! Unlike previous milestone releases, binaries created with Kotlin 1.5.0-RC are guaranteed to be compatible with Kotlin 1.5.0.

Share feedback

This is the final opportunity for you to affect the next feature release! Share any issues you find with us in the issue tracker. Make Kotlin 1.5.0 better for you and the community!

Install 1.5.0-RC

Discover more