Kotlin 1.5.0의 새로운 기능
Kotlin 1.5.0에서는 새로운 언어 기능, 안정화된 IR 기반 JVM 컴파일러 백엔드, 성능 향상, 그리고 실험적 기능의 안정화 및 오래된 기능의 지원 중단과 같은 점진적인 변화가 도입되었습니다.
출시 블로그 포스트에서도 변경 사항에 대한 개요를 확인할 수 있습니다.
Kotlin 출시 주기에 대한 정보는 Kotlin 출시 프로세스를 참조하세요.
언어 기능 (Language features)
Kotlin 1.5.0은 1.4.30에서 미리보기로 선보였던 새로운 언어 기능들의 안정 버전을 제공합니다.
이러한 기능들에 대한 자세한 설명은 이 블로그 포스트와 Kotlin 문서의 해당 페이지에서 확인할 수 있습니다.
JVM 레코드 지원
Java는 빠르게 진화하고 있으며, Kotlin이 Java와 상호 운용성을 유지할 수 있도록 최신 기능 중 하나인 레코드 클래스(record classes)에 대한 지원을 도입했습니다.
Kotlin의 JVM 레코드 지원에는 양방향 상호 운용성이 포함됩니다.
- Kotlin 코드에서는 Java 레코드 클래스를 속성이 있는 일반 클래스처럼 사용할 수 있습니다.
- Java 코드에서 Kotlin 클래스를 레코드로 사용하려면, 해당 클래스를
data클래스로 만들고@JvmRecord어노테이션을 붙이세요.
@JvmRecord
data class User(val name: String, val age: Int)Kotlin에서 JVM 레코드 사용에 대해 더 알아보기.
봉인된 인터페이스 (Sealed interfaces)
이제 Kotlin 인터페이스에 sealed 수정자를 사용할 수 있습니다. 이는 클래스에서 작동하는 방식과 동일하게 인터페이스에서도 작동합니다. 즉, 봉인된 인터페이스의 모든 구현체는 컴파일 타임에 알 수 있습니다.
sealed interface Polygon이 사실을 활용하여, 예를 들어 철저한(exhaustive) when 표현식을 작성할 수 있습니다.
fun draw(polygon: Polygon) = when (polygon) {
is Rectangle -> // ...
is Triangle -> // ...
// else가 필요하지 않음 - 가능한 모든 구현이 처리됨
}또한, 클래스가 둘 이상의 봉인된 인터페이스를 직접 상속할 수 있으므로, 봉인된 인터페이스를 통해 더 유연하게 제한된 클래스 계층 구조를 만들 수 있습니다.
class FilledRectangle: Polygon, Fillable패키지 범위의 봉인된 클래스 계층 구조
이제 동일한 컴파일 단위 및 동일한 패키지의 모든 파일에서 봉인된 클래스의 서브클래스를 가질 수 있습니다. 이전에는 모든 서브클래스가 동일한 파일에 있어야 했습니다.
직접적인 서브클래스는 최상위 수준이거나 임의의 수의 다른 이름이 지정된 클래스, 인터페이스 또는 객체 내부에 중첩될 수 있습니다.
봉인된 클래스의 서브클래스는 적절한 이름(qualified name)을 가져야 하며, 로컬 또는 익명 객체일 수 없습니다.
인라인 클래스 (Inline classes)
인라인 클래스는 값을 하나만 보유하는 값 기반(value-based) 클래스의 하위 집합입니다. 메모리 할당으로 인한 추가 오버헤드 없이 특정 타입의 값에 대한 래퍼(wrapper)로 사용할 수 있습니다.
인라인 클래스는 클래스 이름 앞에 value 수정자를 붙여 선언할 수 있습니다.
value class Password(val s: String)JVM 백엔드에서는 특수한 @JvmInline 어노테이션도 필요합니다.
@JvmInline
value class Password(val s: String)기존의 inline 수정자는 이제 경고와 함께 지원이 중단(deprecated)되었습니다.
Kotlin/JVM
Kotlin/JVM에는 내부적인 개선 사항과 사용자 대면 개선 사항이 모두 포함되었습니다. 가장 주목할 만한 사항은 다음과 같습니다.
- 안정적인 JVM IR 백엔드
- 새로운 기본 JVM 타겟: 1.8
- invokedynamic을 통한 SAM 어댑터
- invokedynamic을 통한 람다
- @JvmDefault 및 이전 Xjvm-default 모드 지원 중단
- 널 허용 여부(nullability) 어노테이션 처리 개선
안정적인 JVM IR 백엔드
Kotlin/JVM 컴파일러를 위한 IR 기반 백엔드가 이제 안정화(Stable)되었으며 기본적으로 활성화됩니다.
Kotlin 1.4.0부터 IR 기반 백엔드의 초기 버전을 미리 볼 수 있었으며, 이제 언어 버전 1.5부터 기본값이 되었습니다. 이전 백엔드는 이전 언어 버전에서 여전히 기본적으로 사용됩니다.
IR 백엔드의 장점과 향후 개발 계획에 대한 자세한 내용은 이 블로그 포스트에서 확인할 수 있습니다.
Kotlin 1.5.0에서 이전 백엔드를 사용해야 하는 경우, 프로젝트 설정 파일에 다음 줄을 추가할 수 있습니다.
- Gradle의 경우:
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
kotlinOptions.useOldBackend = true
}tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile) {
kotlinOptions.useOldBackend = true
}- Maven의 경우:
<configuration>
<args>
<arg>-Xuse-old-backend</arg>
</args>
</configuration>새로운 기본 JVM 타겟: 1.8
Kotlin/JVM 컴파일의 기본 타겟 버전이 이제 1.8이 되었습니다. 1.6 타겟은 지원 중단되었습니다.
JVM 1.6용 빌드가 필요한 경우 여전히 이 타겟으로 전환할 수 있습니다. 방법은 다음과 같습니다.
invokedynamic을 통한 SAM 어댑터
Kotlin 1.5.0은 이제 SAM(Single Abstract Method) 변환을 컴파일할 때 동적 호출(invokedynamic)을 사용합니다.
- SAM 타입이 Java 인터페이스인 경우 모든 표현식에 대해 적용됩니다.
- SAM 타입이 Kotlin 함수형 인터페이스인 경우 람다에 대해 적용됩니다.
새로운 구현은 LambdaMetafactory.metafactory()를 사용하며, 컴파일 중에 더 이상 보조 래퍼 클래스가 생성되지 않습니다. 이를 통해 애플리케이션의 JAR 크기가 줄어들어 JVM 시작 성능이 향상됩니다.
익명 클래스 생성을 기반으로 하는 이전 구현 방식으로 되돌리려면 컴파일러 옵션 -Xsam-conversions=class를 추가하세요.
Gradle, Maven, 명령줄 컴파일러에서 컴파일러 옵션을 추가하는 방법을 알아보세요.
invokedynamic을 통한 람다
일반 Kotlin 람다를
invokedynamic으로 컴파일하는 기능은 실험적(Experimental)입니다. 이는 언제든지 삭제되거나 변경될 수 있습니다. 옵트인(Opt-in)이 필요하며(아래 상세 내용 참조), 평가 목적으로만 사용해야 합니다. YouTrack을 통해 이에 대한 의견을 보내주시면 감사하겠습니다.
Kotlin 1.5.0은 일반 Kotlin 람다(함수형 인터페이스의 인스턴스로 변환되지 않는 람다)를 동적 호출(invokedynamic)로 컴파일하는 실험적 지원을 도입합니다. 이 구현은 런타임에 필요한 클래스를 효과적으로 생성하는 LambdaMetafactory.metafactory()를 사용하여 더 가벼운 바이너리를 생성합니다. 현재 일반적인 람다 컴파일과 비교하여 세 가지 제한 사항이 있습니다.
invokedynamic으로 컴파일된 람다는 직렬화할 수 없습니다.- 이러한 람다에서
toString()을 호출하면 가독성이 떨어지는 문자열 표현이 생성됩니다. - 실험적인
reflectAPI는LambdaMetafactory로 생성된 람다를 지원하지 않습니다.
이 기능을 시도하려면 -Xlambdas=indy 컴파일러 옵션을 추가하세요. 이 YouTrack 티켓을 통해 피드백을 공유해 주시면 감사하겠습니다.
Gradle, Maven, 명령줄 컴파일러에서 컴파일러 옵션을 추가하는 방법을 알아보세요.
@JvmDefault 및 이전 Xjvm-default 모드 지원 중단
Kotlin 1.4.0 이전에는 -Xjvm-default=enable 및 -Xjvm-default=compatibility 모드와 함께 @JvmDefault 어노테이션이 있었습니다. 이들은 Kotlin 인터페이스의 특정 비추상 멤버에 대해 JVM 기본 메서드(default method)를 만드는 데 사용되었습니다.
Kotlin 1.4.0에서는 전체 프로젝트에 대해 기본 메서드 생성을 활성화하는 새로운 Xjvm-default 모드를 도입했습니다.
Kotlin 1.5.0에서는 @JvmDefault와 이전 Xjvm-default 모드인 -Xjvm-default=enable 및 -Xjvm-default=compatibility를 지원 중단합니다.
Java 상호 운용성에서의 기본 메서드에 대해 더 알아보기.
널 허용 여부(nullability) 어노테이션 처리 개선
Kotlin은 널 허용 여부 어노테이션을 통해 Java의 타입 널 허용 여부 정보 처리를 지원합니다. Kotlin 1.5.0에서는 이 기능에 대한 여러 개선 사항이 도입되었습니다.
- 종속성으로 사용되는 컴파일된 Java 라이브러리의 타입 인자에 있는 널 허용 여부 어노테이션을 읽습니다.
- 다음 항목에 대해
TYPE_USE타겟이 있는 널 허용 여부 어노테이션을 지원합니다.- 배열(Arrays)
- 가변 인자(Varargs)
- 필드(Fields)
- 타입 파라미터 및 그 경계(bounds)
- 베이스 클래스 및 인터페이스의 타입 인자
- 널 허용 여부 어노테이션에 타입에 적용 가능한 여러 타겟이 있고 그 중 하나가
TYPE_USE인 경우,TYPE_USE가 우선적으로 사용됩니다. 예를 들어,@Nullable이TYPE_USE와METHOD를 모두 타겟으로 지원한다면 메서드 시그니처@Nullable String[] f()는fun f(): Array<String?>!가 됩니다.
새롭게 지원되는 이러한 경우에 대해 Kotlin에서 Java를 호출할 때 잘못된 타입 널 허용 여부를 사용하면 경고가 발생합니다. 이러한 경우에 대해 엄격 모드(strict mode, 오류 보고 포함)를 활성화하려면 -Xtype-enhancement-improvements-strict-mode 컴파일러 옵션을 사용하세요.
Kotlin/Native
Kotlin/Native는 이제 성능과 안정성이 더욱 향상되었습니다. 주목할 만한 변경 사항은 다음과 같습니다.
성능 향상
1.5.0에서 Kotlin/Native는 컴파일과 실행 속도를 모두 높이는 일련의 성능 개선 사항을 적용받았습니다.
컴파일러 캐시가 이제 linuxX64(Linux 호스트에서만) 및 iosArm64 타겟의 디버그 모드에서 지원됩니다. 컴파일러 캐시를 활성화하면 첫 번째 컴파일을 제외한 대부분의 디버그 컴파일이 훨씬 빠르게 완료됩니다. 테스트 프로젝트 측정 결과 약 200%의 속도 향상을 보였습니다.
새로운 타겟에 대해 컴파일러 캐시를 사용하려면 프로젝트의 gradle.properties에 다음 줄을 추가하여 옵트인하세요.
linuxX64타겟:kotlin.native.cacheKind.linuxX64=staticiosArm64타겟:kotlin.native.cacheKind.iosArm64=static
컴파일러 캐시를 활성화한 후 문제가 발생하면 이슈 트래커인 YouTrack에 보고해 주세요.
다른 개선 사항들은 Kotlin/Native 코드의 실행 속도를 높여줍니다.
- 사소한 속성 접근자(trivial property accessors)가 인라인화됩니다.
- 문자열 리터럴의
trimIndent()가 컴파일 중에 평가됩니다.
메모리 누수 검사기 비활성화
내장된 Kotlin/Native 메모리 누수 검사기가 기본적으로 비활성화되었습니다.
이 검사기는 원래 내부용으로 설계되었으며, 모든 경우가 아닌 제한된 수의 사례에서만 누수를 찾을 수 있습니다. 또한, 나중에 애플리케이션 충돌을 일으킬 수 있는 이슈가 있는 것으로 밝혀졌습니다. 따라서 메모리 누수 검사기를 끄기로 결정했습니다.
메모리 누수 검사기는 유닛 테스트와 같은 특정 사례에서 여전히 유용할 수 있습니다. 이러한 경우 다음 코드 줄을 추가하여 활성화할 수 있습니다.
Platform.isMemoryLeakCheckerActive = true애플리케이션 런타임에 대해 검사기를 활성화하는 것은 권장되지 않습니다.
Kotlin/JS
Kotlin/JS는 1.5.0에서 점진적인 변화를 맞이하고 있습니다. JS IR 컴파일러 백엔드를 안정화 단계로 옮기기 위한 작업을 계속하고 있으며 다른 업데이트들도 배포하고 있습니다.
webpack 5로 업그레이드
이제 Kotlin/JS Gradle 플러그인은 브라우저 타겟에 대해 webpack 4 대신 webpack 5를 사용합니다. 이는 호환되지 않는 변경 사항을 포함하는 주요 webpack 업그레이드입니다. 사용자 정의 webpack 설정을 사용 중이라면 webpack 5 출시 노트를 반드시 확인하세요.
webpack을 사용한 Kotlin/JS 프로젝트 번들링에 대해 더 알아보기.
IR 컴파일러용 프레임워크 및 라이브러리
Kotlin/JS IR 컴파일러는 알파(Alpha) 단계에 있습니다. 향후 호환되지 않는 변경이 발생할 수 있으며 수동 마이그레이션이 필요할 수 있습니다. YouTrack을 통해 의견을 보내주시면 감사하겠습니다.
Kotlin/JS 컴파일러용 IR 기반 백엔드 작업과 함께, 라이브러리 저자들이 프로젝트를 both 모드로 빌드하도록 장려하고 돕고 있습니다. 이는 두 Kotlin/JS 컴파일러 모두를 위한 아티팩트를 생성할 수 있음을 의미하며, 결과적으로 새 컴파일러를 위한 생태계를 성장시킵니다.
KVision, fritz2, doodle 등 이미 많은 유명 프레임워크와 라이브러리가 IR 백엔드에서 사용 가능합니다. 프로젝트에서 이러한 라이브러리를 사용하고 있다면 이미 IR 백엔드로 빌드하여 그 이점을 확인할 수 있습니다.
직접 라이브러리를 작성하고 있다면 'both' 모드로 컴파일하여 사용자가 새 컴파일러에서도 해당 라이브러리를 사용할 수 있도록 하세요.
Kotlin 멀티플랫폼
Kotlin 1.5.0에서는 각 플랫폼에 대한 테스트 종속성 선택이 단순화되었으며, 이제 Gradle 플러그인에 의해 자동으로 수행됩니다.
새로운 문자 카테고리를 가져오기 위한 API가 이제 멀티플랫폼 프로젝트에서 사용 가능합니다.
표준 라이브러리 (Standard library)
표준 라이브러리는 실험적 기능의 안정화부터 새로운 기능 추가에 이르기까지 다양한 변경과 개선이 이루어졌습니다.
- 안정적인 부호 없는 정수 타입
- 대소문자 변환을 위한 안정적인 로케일 중립적 API
- 안정적인 Char-to-integer 변환 API
- 안정적인 Path API
- 내림 나눗셈(Floored division) 및 mod 연산자
- Duration API 변경 사항
- 멀티플랫폼 코드에서 문자 카테고리를 가져오기 위한 새로운 API 사용 가능
- 새로운 컬렉션 함수 firstNotNullOf()
- String?.toBoolean()의 엄격한 버전
표준 라이브러리 변경 사항에 대한 자세한 내용은 이 블로그 포스트에서 확인할 수 있습니다.
안정적인 부호 없는 정수 타입
UInt, ULong, UByte, UShort 부호 없는 정수 타입이 이제 안정화(Stable)되었습니다. 이러한 타입에 대한 연산, 범위(ranges), 진행(progressions)도 마찬가지입니다. 부호 없는 배열 및 그 연산은 베타 단계로 유지됩니다.
대소문자 변환을 위한 안정적인 로케일 중립적 API
이번 릴리스에서는 대소문자 텍스트 변환을 위한 로케일에 무관한(locale-agnostic) 새로운 API를 도입했습니다. 이는 로케일에 민감한 toLowerCase(), toUpperCase(), capitalize(), decapitalize() API 함수에 대한 대안을 제공합니다. 새로운 API를 사용하면 서로 다른 로케일 설정으로 인한 오류를 피할 수 있습니다.
Kotlin 1.5.0은 다음과 같이 완전히 안정적인(Stable) 대안을 제공합니다.
String함수의 경우:이전 버전 1.5.0 대안 String.toUpperCase()String.uppercase()String.toLowerCase()String.lowercase()String.capitalize()String.replaceFirstChar { it.uppercase() }String.decapitalize()String.replaceFirstChar { it.lowercase() }Char함수의 경우:이전 버전 1.5.0 대안 Char.toUpperCase()Char.uppercaseChar(): CharChar.uppercase(): StringChar.toLowerCase()Char.lowercaseChar(): CharChar.lowercase(): StringChar.toTitleCase()Char.titlecaseChar(): CharChar.titlecase(): String
Kotlin/JVM의 경우 명시적인
Locale파라미터를 갖는 오버로드된uppercase(),lowercase(),titlecase()함수도 있습니다.
기존의 API 함수들은 지원 중단으로 표시되었으며 향후 릴리스에서 제거될 예정입니다.
텍스트 처리 함수의 전체 변경 목록은 KEEP에서 확인하세요.
안정적인 Char-to-integer 변환 API
Kotlin 1.5.0부터 새로운 char-to-code 및 char-to-digit 변환 함수가 안정화되었습니다. 이 함수들은 종종 유사한 string-to-Int 변환과 혼동되었던 기존 API 함수들을 대체합니다.
새로운 API는 이러한 명명 혼란을 제거하여 코드 동작을 더 투명하고 명확하게 만듭니다.
이번 릴리스에서는 다음과 같이 명확하게 명명된 함수 세트로 나누어진 Char 변환을 도입합니다.
Char의 정수 코드를 가져오고 주어진 코드에서Char를 구성하는 함수:
fun Char(code: Int): Char
fun Char(code: UShort): Char
val Char.code: IntChar를 그것이 나타내는 숫자의 수치 값으로 변환하는 함수:
fun Char.digitToInt(radix: Int): Int
fun Char.digitToIntOrNull(radix: Int): Int?Int에 대한 확장 함수로, 그것이 나타내는 음이 아닌 단일 숫자를 해당하는Char표현으로 변환하는 함수:
fun Int.digitToChar(radix: Int): CharInt.toChar()를 제외한 모든 구현을 포함하는 Number.toChar()와 Char.toInt()와 같이 수치 타입으로의 변환을 위한 Char 확장 함수를 포함한 기존 변환 API들은 이제 지원 중단되었습니다.
KEEP에서 char-to-integer 변환 API에 대해 더 알아보기.
안정적인 Path API
java.nio.file.Path에 대한 확장 기능을 포함한 실험적인 Path API가 이제 안정화되었습니다.
// div (/) 연산자로 경로 구성
val baseDir = Path("/base")
val subDir = baseDir / "subdirectory"
// 디렉토리 내 파일 목록 나열
val kotlinFiles: List<Path> = Path("/home/user").listDirectoryEntries("*.kt")내림 나눗셈(Floored division) 및 mod 연산자
모듈러 산술(modular arithmetics)을 위한 새로운 연산이 표준 라이브러리에 추가되었습니다.
floorDiv()는 내림 나눗셈(floored division)의 결과를 반환합니다. 정수 타입에 대해 사용할 수 있습니다.mod()는 내림 나눗셈의 나머지(modulus)를 반환합니다. 모든 수치 타입에 대해 사용할 수 있습니다.
이러한 연산은 기존의 정수 나눗셈 및 rem() 함수(또는 % 연산자)와 매우 유사해 보이지만, 음수에 대해 다르게 작동합니다.
a.floorDiv(b)는floorDiv가 결과를 내림(더 작은 정수 쪽으로)하는 반면,/는 결과를 0에 더 가까운 정수로 자른다(truncate)는 점에서 일반적인/와 다릅니다.a.mod(b)는a와a.floorDiv(b) * b사이의 차이입니다. 결과는 0이거나b와 같은 부호를 갖는 반면,a % b는 다른 부호를 가질 수 있습니다.
fun main() {
println("내림 나눗셈 -5/3: ${(-5).floorDiv(3)}")
println( "나머지(Modulus): ${(-5).mod(3)}")
println("절삭 나눗셈 -5/3: ${-5 / 3}")
println( "나머지(Remainder): ${-5 % 3}")
}Duration API 변경 사항
Duration API는 실험적(Experimental)입니다. 이는 언제든지 삭제되거나 변경될 수 있습니다. 평가 목적으로만 사용하세요. YouTrack을 통해 이에 대한 의견을 보내주시면 감사하겠습니다.
다양한 시간 단위로 기간(duration) 양을 표현하기 위한 실험적인 Duration 클래스가 있습니다. 1.5.0에서 Duration API는 다음과 같은 변경 사항이 적용되었습니다.
- 내부 값 표현에
Double대신Long을 사용하여 더 나은 정밀도를 제공합니다. Long타입의 특정 시간 단위로 변환하기 위한 새로운 API가 도입되었습니다. 이는Double값으로 작동하며 현재 지원 중단된 기존 API를 대체합니다. 예를 들어,Duration.inWholeMinutes는Long으로 표현된 기간 값을 반환하며Duration.inMinutes를 대체합니다.- 숫자로부터
Duration을 구성하기 위한 새로운 동반(companion) 함수들이 추가되었습니다. 예를 들어,Duration.seconds(Int)는 정수 초를 나타내는Duration객체를 생성합니다.Int.seconds와 같은 기존 확장 속성들은 이제 지원 중단되었습니다.
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
@ExperimentalTime
fun main() {
val duration = Duration.milliseconds(120000)
println("${duration.inWholeMinutes}분은 ${duration.inWholeSeconds}초입니다.")
}멀티플랫폼 코드에서 문자 카테고리를 가져오기 위한 새로운 API 사용 가능
Kotlin 1.5.0은 멀티플랫폼 프로젝트에서 Unicode에 따른 문자의 카테고리를 가져오기 위한 새로운 API를 도입했습니다. 이제 여러 함수를 모든 플랫폼과 공통 코드에서 사용할 수 있습니다.
문자가 문자인지 숫자인지 확인하는 함수:
fun main() {
val chars = listOf('a', '1', '+')
val (letterOrDigitList, notLetterOrDigitList) = chars.partition { it.isLetterOrDigit() }
println(letterOrDigitList) // [a, 1]
println(notLetterOrDigitList) // [+]
}문자의 대소문자를 확인하는 함수:
fun main() {
val chars = listOf('Dž', 'Lj', 'Nj', 'Dz', '1', 'A', 'a', '+')
val (titleCases, notTitleCases) = chars.partition { it.isTitleCase() }
println(titleCases) // [Dž, Lj, Nj, Dz]
println(notTitleCases) // [1, A, a, +]
}기타 함수:
Unicode에 따른 문자의 일반 카테고리를 나타내는 Char.category 속성과 그 반환 타입인 CharCategory 열거형 클래스도 이제 멀티플랫폼 프로젝트에서 사용할 수 있습니다.
새로운 컬렉션 함수 firstNotNullOf()
새로운 firstNotNullOf() 및 firstNotNullOfOrNull() 함수는 mapNotNull()을 first() 또는 firstOrNull()과 결합한 것입니다. 이 함수들은 사용자 정의 선택자 함수를 사용하여 원본 컬렉션을 매핑하고 null이 아닌 첫 번째 값을 반환합니다. 만약 그러한 값이 없으면 firstNotNullOf()는 예외를 던지고, firstNotNullOfOrNull()은 null을 반환합니다.
fun main() {
val data = listOf("Kotlin", "1.5")
println(data.firstNotNullOf(String::toDoubleOrNull))
println(data.firstNotNullOfOrNull(String::toIntOrNull))
}String?.toBoolean()의 엄격한 버전
기존의 String?.toBoolean()에 대한 대소문자를 구분하는 엄격한 버전인 두 가지 새로운 함수가 도입되었습니다.
String.toBooleanStrict()는 리터럴true및false를 제외한 모든 입력에 대해 예외를 던집니다.String.toBooleanStrictOrNull()은 리터럴true및false를 제외한 모든 입력에 대해 null을 반환합니다.
fun main() {
println("true".toBooleanStrict())
println("1".toBooleanStrictOrNull())
// println("1".toBooleanStrict()) // 예외 발생
}kotlin-test 라이브러리
kotlin-test 라이브러리에 몇 가지 새로운 기능이 도입되었습니다.
멀티플랫폼 프로젝트에서 테스트 종속성 사용 간소화
이제 commonTest 소스 세트에서 테스트를 위한 종속성을 추가할 때 kotlin-test 종속성을 사용할 수 있으며, Gradle 플러그인이 각 테스트 소스 세트에 해당하는 플랫폼 종속성을 추론합니다.
- JVM 소스 세트의 경우
kotlin-test-junit. Kotlin/JVM 소스 세트에 대한 테스트 프레임워크 자동 선택을 참조하세요. - Kotlin/JS 소스 세트의 경우
kotlin-test-js - 공통 소스 세트의 경우
kotlin-test-common및kotlin-test-annotations-common - Kotlin/Native 소스 세트의 경우 별도의 아티팩트 없음
또한, 공유 또는 플랫폼별 소스 세트에서도 kotlin-test 종속성을 사용할 수 있습니다.
명시적 종속성이 있는 기존의 kotlin-test 설정은 Gradle 및 Maven 모두에서 계속 작동합니다.
테스트 라이브러리에 대한 종속성 설정에 대해 더 알아보세요.
Kotlin/JVM 소스 세트에 대한 테스트 프레임워크 자동 선택
이제 Gradle 플러그인이 테스트 프레임워크에 대한 종속성을 자동으로 선택하고 추가합니다. 공통 소스 세트에 kotlin-test 종속성만 추가하면 됩니다.
Gradle은 기본적으로 JUnit 4를 사용합니다. 따라서 kotlin("test") 종속성은 JUnit 4용 변체인 kotlin-test-junit으로 해석됩니다.
kotlin {
sourceSets {
val commonTest by getting {
dependencies {
implementation(kotlin("test")) // 이 코드는 전이적으로
// JUnit 4에 대한 종속성을 가져옵니다.
}
}
}
}kotlin {
sourceSets {
commonTest {
dependencies {
implementation kotlin("test") // 이 코드는 전이적으로
// JUnit 4에 대한 종속성을 가져옵니다.
}
}
}
}테스트 태스크에서 useJUnitPlatform() 또는 useTestNG()를 호출하여 JUnit 5 또는 TestNG를 선택할 수 있습니다.
tasks {
test {
// TestNG 지원 활성화
useTestNG()
// 또는
// JUnit Platform (JUnit 5) 지원 활성화
useJUnitPlatform()
}
}프로젝트의 gradle.properties에 kotlin.test.infer.jvm.variant=false 라인을 추가하여 테스트 프레임워크 자동 선택을 비활성화할 수 있습니다.
테스트 라이브러리에 대한 종속성 설정에 대해 더 알아보세요.
단언문(Assertion) 함수 업데이트
이번 릴리스에서는 새로운 단언문 함수들이 추가되고 기존 함수들이 개선되었습니다.
kotlin-test 라이브러리에 추가된 기능은 다음과 같습니다.
값의 타입 확인
값의 타입을 확인하기 위해 새로운
assertIs<T>및assertIsNot<T>를 사용할 수 있습니다.kotlin@Test fun testFunction() { val s: Any = "test" assertIs<String>(s) // 단언이 실패하면 s의 실제 타입을 언급하는 AssertionError를 던집니다. // assertIs의 계약(contract) 덕분에 이제 s.length를 출력할 수 있습니다. println("${s.length}") }타입 소거(type erasure) 때문에, 다음 예제에서 이 단언 함수는
value가List타입인지만 확인하며 특정String요소 타입의 리스트인지는 확인하지 않습니다:assertIs<List<String>>(value).배열, 시퀀스 및 임의의 이터러블에 대한 컨테이너 내용 비교
구조적 동등성(structural equality)을 구현하지 않는 다양한 컬렉션의 내용을 비교하기 위한 새로운 오버로드된
assertContentEquals()함수 세트가 추가되었습니다.kotlin@Test fun test() { val expectedArray = arrayOf(1, 2, 3) val actualArray = Array(3) { it + 1 } assertContentEquals(expectedArray, actualArray) }Double및Float숫자에 대한assertEquals()및assertNotEquals()의 새로운 오버로드두 개의
Double또는Float숫자를 절대 정밀도로 비교할 수 있게 해주는assertEquals()함수의 새로운 오버로드가 추가되었습니다. 정밀도 값은 함수의 세 번째 파라미터로 지정됩니다.kotlin@Test fun test() { val x = sin(PI) // 정밀도 파라미터 val tolerance = 0.000001 assertEquals(0.0, x, tolerance) }컬렉션 및 요소의 내용을 확인하기 위한 새로운 함수
이제
assertContains()함수를 사용하여 컬렉션이나 요소에 무언가가 포함되어 있는지 확인할 수 있습니다.IntRange,String등contains()연산자가 있는 Kotlin 컬렉션 및 요소와 함께 사용할 수 있습니다.kotlin@Test fun test() { val sampleList = listOf<String>("sample", "sample2") val sampleString = "sample" assertContains(sampleList, sampleString) // 컬렉션 내 요소 확인 assertContains(sampleString, "amp") // 문자열 내 부분 문자열 확인 }이제
assertTrue(),assertFalse(),expect()함수가 인라인화됨이제부터 이 함수들을 인라인 함수로 사용할 수 있으므로, 람다 표현식 내부에서 일시 중단 함수(suspend functions)를 호출할 수 있습니다.
kotlin@Test fun test() = runBlocking<Unit> { val deferred = async { "Kotlin is nice" } assertTrue("Kotlin 부분 문자열이 존재해야 함") { deferred.await() .contains("Kotlin") } }
kotlinx 라이브러리
Kotlin 1.5.0과 함께 kotlinx 라이브러리의 새로운 버전들도 출시되었습니다.
Coroutines 1.5.0-RC
kotlinx.coroutines 1.5.0-RC의 주요 변경 사항은 다음과 같습니다.
Kotlin 1.5.0부터 실험적 코루틴(experimental coroutines)은 비활성화되며 -Xcoroutines=experimental 플래그는 더 이상 지원되지 않습니다.
자세한 내용은 변경 로그와 kotlinx.coroutines 1.5.0 출시 블로그 포스트에서 확인하세요.
Serialization 1.2.1
kotlinx.serialization 1.2.1의 주요 변경 사항은 다음과 같습니다.
- JSON 직렬화 성능 개선
- JSON 직렬화 시 여러 이름(multiple names) 지원
@Serializable클래스로부터 실험적인 .proto 스키마 생성 지원- 기타 등등
자세한 내용은 변경 로그와 kotlinx.serialization 1.2.1 출시 블로그 포스트에서 확인하세요.
dateTime 0.2.0
kotlinx-datetime 0.2.0의 주요 변경 사항은 다음과 같습니다.
@Serializable적용이 가능한 Datetime 객체- 정규화된
DateTimePeriod및DatePeriodAPI - 기타 등등
자세한 내용은 변경 로그와 kotlinx-datetime 0.2.0 출시 블로그 포스트에서 확인하세요.
Kotlin 1.5.0으로 마이그레이션
IntelliJ IDEA와 Android Studio는 Kotlin 1.5.0 플러그인이 사용 가능해지면 업데이트를 제안할 것입니다.
기존 프로젝트를 Kotlin 1.5.0으로 마이그레이션하려면 Kotlin 버전을 1.5.0으로 변경하고 Gradle 또는 Maven 프로젝트를 다시 가져오기만 하면 됩니다. Kotlin 1.5.0으로 업데이트하는 방법을 알아보세요.
Kotlin 1.5.0으로 새 프로젝트를 시작하려면 Kotlin 플러그인을 업데이트하고 File | New | Project에서 프로젝트 마법사를 실행하세요.
새로운 명령줄 컴파일러는 GitHub 출시 페이지에서 다운로드할 수 있습니다.
Kotlin 1.5.0은 기능 릴리스(feature release)이므로 언어에 호환되지 않는 변경 사항이 포함될 수 있습니다. 이러한 변경 사항의 상세 목록은 Kotlin 1.5 호환성 가이드에서 확인할 수 있습니다.
