Skip to content

Kotlin 1.5.20의 새로운 기능

출시일: 2021년 6월 24일

Kotlin 1.5.20에는 1.5.0의 새로운 기능에서 발견된 문제에 대한 수정 사항이 포함되어 있으며, 다양한 툴링 개선 사항도 포함되어 있습니다.

이러한 변경 사항에 대한 개요는 릴리스 블로그 게시물 및 다음 비디오에서 확인할 수 있습니다:

Kotlin/JVM

Kotlin 1.5.20은 JVM 플랫폼에서 다음과 같은 업데이트를 제공합니다:

invokedynamic을 통한 문자열 연결

Kotlin 1.5.20은 JVM 9 이상을 대상으로 하는 환경에서 문자열 연결을 동적 호출 (invokedynamic)로 컴파일하여 최신 Java 버전과 보조를 맞춥니다. 더 정확히 말하면, 문자열 연결을 위해 StringConcatFactory.makeConcatWithConstants()를 사용합니다.

이전 버전에서 사용되던 StringBuilder.append()를 통한 연결로 다시 전환하려면 컴파일러 옵션 -Xstring-concat=inline을 추가하세요.

Gradle, Maven명령줄 컴파일러에서 컴파일러 옵션을 추가하는 방법을 알아보세요.

JSpecify 널 가능성 어노테이션 지원

Kotlin 컴파일러는 Java에서 Kotlin으로 널 가능성 정보를 전달하기 위해 다양한 유형의 널 가능성 어노테이션을 읽을 수 있습니다. 버전 1.5.20은 표준 통합 Java 널 가능성 어노테이션 세트를 포함하는 JSpecify 프로젝트에 대한 지원을 도입합니다.

JSpecify를 사용하면 Kotlin이 Java와 널 안전성(null-safety)을 상호 운용하는 데 도움이 되도록 더 자세한 널 가능성 정보를 제공할 수 있습니다. 선언, 패키지 또는 모듈 범위에 대한 기본 널 가능성을 설정하고, 매개변수 널 가능성을 지정하는 등 다양한 작업을 수행할 수 있습니다. 이에 대한 자세한 내용은 JSpecify 사용자 가이드에서 확인할 수 있습니다.

다음은 Kotlin이 JSpecify 어노테이션을 처리하는 방법의 예시입니다:

java
// JavaClass.java
import org.jspecify.nullness.*;

@NullMarked
public class JavaClass {
  public String notNullableString() { return ""; }
  public @Nullable String nullableString() { return ""; }
}
kotlin
// Test.kt
fun kotlinFun() = with(JavaClass()) {
  notNullableString().length // OK
  nullableString().length    // Warning: receiver nullability mismatch
}

1.5.20에서는 JSpecify에서 제공하는 널 가능성 정보에 따른 모든 널 가능성 불일치(nullability mismatches)가 경고로 보고됩니다. JSpecify를 사용할 때 엄격 모드(오류 보고 포함)를 활성화하려면 -Xjspecify-annotations=strict-Xtype-enhancement-improvements-strict-mode 컴파일러 옵션을 사용하세요. JSpecify 프로젝트는 활발하게 개발 중이며, API와 구현은 언제든지 크게 변경될 수 있음을 유의하십시오.

널 안전성(null-safety) 및 플랫폼 타입에 대해 자세히 알아보세요.

Kotlin 및 Java 코드를 포함하는 모듈 내에서 Java의 Lombok으로 생성된 메서드 호출 지원

DANGER

Lombok 컴파일러 플러그인은 실험적 기능입니다.

언제든지 중단되거나 변경될 수 있습니다. 평가 목적으로만 사용하십시오.

이에 대한 피드백을 YouTrack에 남겨주시면 감사하겠습니다.

Kotlin 1.5.20은 실험적 Lombok 컴파일러 플러그인을 도입합니다. 이 플러그인을 사용하면 Kotlin 및 Java 코드를 포함하는 모듈 내에서 Java의 Lombok 선언을 생성하고 사용할 수 있습니다. Lombok 어노테이션은 Java 소스에서만 작동하며 Kotlin 코드에서 사용하면 무시됩니다.

이 플러그인은 다음 어노테이션을 지원합니다:

  • @Getter, @Setter
  • @NoArgsConstructor, @RequiredArgsConstructor, and @AllArgsConstructor
  • @Data
  • @With
  • @Value

저희는 이 플러그인에 대한 작업을 계속하고 있습니다. 자세한 현재 상태는 Lombok 컴파일러 플러그인 README에서 확인할 수 있습니다.

현재 @Builder 어노테이션을 지원할 계획은 없습니다. 하지만 YouTrack에서 @Builder에 투표해주시면 고려해볼 수 있습니다.

Lombok 컴파일러 플러그인을 구성하는 방법을 알아보세요.

Kotlin/Native

Kotlin/Native 1.5.20은 새로운 기능 및 툴링 개선 사항에 대한 미리 보기를 제공합니다:

KDoc 주석을 생성된 Objective-C 헤더로 옵트인 내보내기

DANGER

KDoc 주석을 생성된 Objective-C 헤더로 내보내는 기능은 실험적 기능입니다.

언제든지 중단되거나 변경될 수 있습니다.

옵트인(자세한 내용은 아래 참조)이 필요하며, 평가 목적으로만 사용해야 합니다.

이에 대한 피드백을 YouTrack에 남겨주시면 감사하겠습니다.

이제 Kotlin/Native 컴파일러가 Kotlin 코드의 문서 주석(KDoc)을 생성된 Objective-C 프레임워크로 내보내어, 해당 프레임워크 사용자가 주석을 볼 수 있도록 설정할 수 있습니다.

예를 들어, KDoc이 포함된 다음 Kotlin 코드는:

kotlin
/**
 * Prints the sum of the arguments.
 * Properly handles the case when the sum doesn't fit in 32-bit integer.
 */
fun printSum(a: Int, b: Int) = println(a.toLong() + b)

다음 Objective-C 헤더를 생성합니다:

objc
/**
 * Prints the sum of the arguments.
 * Properly handles the case when the sum doesn't fit in 32-bit integer.
 */
+ (void)printSumA:(int32_t)a b:(int32_t)b __attribute__((swift_name("printSum(a:b:)")));

이것은 Swift에서도 잘 작동합니다.

KDoc 주석을 Objective-C 헤더로 내보내는 이 기능을 사용해보려면 -Xexport-kdoc 컴파일러 옵션을 사용하세요. 주석을 내보내려는 Gradle 프로젝트의 build.gradle(.kts)에 다음 줄을 추가하세요:

kotlin
kotlin {
    targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
        compilations.get("main").kotlinOptions.freeCompilerArgs += "-Xexport-kdoc"
    }
}
groovy
kotlin {
    targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget) {
        compilations.get("main").kotlinOptions.freeCompilerArgs += "-Xexport-kdoc"
    }
}

YouTrack 티켓을 사용하여 피드백을 공유해주시면 매우 감사하겠습니다.

컴파일러 버그 수정

Kotlin/Native 컴파일러는 1.5.20에서 여러 버그 수정 사항을 받았습니다. 전체 목록은 변경 로그에서 확인할 수 있습니다.

호환성에 영향을 미치는 중요한 버그 수정이 있습니다. 이전 버전에서는 잘못된 UTF 대리쌍(surrogate pairs)을 포함하는 문자열 상수가 컴파일 중에 값을 잃었습니다. 이제 이러한 값은 보존됩니다. 애플리케이션 개발자는 1.5.20으로 안전하게 업데이트할 수 있으며 아무것도 깨지지 않습니다. 하지만 1.5.20으로 컴파일된 라이브러리는 이전 컴파일러 버전과 호환되지 않습니다. 자세한 내용은 이 YouTrack 이슈를 참조하십시오.

단일 배열 내 Array.copyInto() 성능 향상

소스와 대상이 동일한 배열일 때 Array.copyInto()가 작동하는 방식을 개선했습니다. 이제 이러한 작업은 이 사용 사례에 대한 메모리 관리 최적화 덕분에 최대 20배 더 빠르게 완료됩니다(복사되는 객체 수에 따라 다름).

Kotlin/JS

1.5.20에서는 Kotlin/JS의 새로운 IR 기반 백엔드로 프로젝트를 마이그레이션하는 데 도움이 되는 가이드를 발행합니다.

JS IR 백엔드 마이그레이션 가이드

새로운 JS IR 백엔드 마이그레이션 가이드는 마이그레이션 중에 발생할 수 있는 문제를 식별하고 이에 대한 해결책을 제공합니다. 가이드에 포함되지 않은 문제가 발견되면 이슈 트래커에 보고해 주십시오.

Gradle

Kotlin 1.5.20은 Gradle 경험을 향상시킬 수 있는 다음 기능을 도입합니다:

kapt의 어노테이션 프로세서 클래스로더 캐싱

DANGER

kapt의 어노테이션 프로세서 클래스로더 캐싱은 실험적 기능입니다.

언제든지 중단되거나 변경될 수 있습니다. 평가 목적으로만 사용하십시오.

이에 대한 피드백을 YouTrack에 남겨주시면 감사하겠습니다.

이제 kapt에서 어노테이션 프로세서의 클래스로더를 캐싱할 수 있게 해주는 새로운 실험적 기능이 있습니다. 이 기능은 연속적인 Gradle 실행 시 kapt 속도를 높일 수 있습니다.

이 기능을 활성화하려면 gradle.properties 파일에 다음 속성을 사용하십시오:

none
# positive value will enable caching
# use the same value as the number of modules that use kapt
kapt.classloaders.cache.size=5

# disable for caching to work
kapt.include.compile.classpath=false

kapt에 대해 자세히 알아보세요.

kotlin.parallel.tasks.in.project 빌드 속성 사용 중단

이번 릴리스부터 Kotlin 병렬 컴파일은 Gradle 병렬 실행 플래그 --parallel에 의해 제어됩니다. 이 플래그를 사용하면 Gradle은 작업을 동시에 실행하여 컴파일 작업 속도를 높이고 리소스를 더 효율적으로 활용합니다.

더 이상 kotlin.parallel.tasks.in.project 속성을 사용할 필요가 없습니다. 이 속성은 사용이 중단되었으며 다음 주요 릴리스에서 제거될 예정입니다.

표준 라이브러리

Kotlin 1.5.20은 문자를 다루는 여러 함수의 플랫폼별 구현을 변경하여 플랫폼 간의 통일성을 가져옵니다:

Kotlin/Native 및 Kotlin/JS에서 Char.digitToInt()의 모든 유니코드 숫자 지원

Char.digitToInt()는 문자가 나타내는 10진수 숫자의 값을 반환합니다. 1.5.20 이전에는 이 함수가 Kotlin/JVM에서만 모든 유니코드 숫자 문자를 지원했으며, Native 및 JS 플랫폼의 구현은 ASCII 숫자만 지원했습니다.

이제 Kotlin/Native와 Kotlin/JS 모두에서 모든 유니코드 숫자 문자에 대해 Char.digitToInt()를 호출하고 해당 숫자 표현을 얻을 수 있습니다.

kotlin
fun main() {
    val ten = '\u0661'.digitToInt() + '\u0039'.digitToInt() // ARABIC-INDIC DIGIT ONE + DIGIT NINE
    println(ten)
}

플랫폼 전반에 걸친 Char.isLowerCase()/isUpperCase() 구현 통일

Char.isUpperCase()Char.isLowerCase() 함수는 문자의 대소문자에 따라 불리언 값을 반환합니다. Kotlin/JVM의 경우, 구현은 General_CategoryOther_Uppercase/Other_Lowercase 유니코드 속성을 모두 확인합니다.

1.5.20 이전에는 다른 플랫폼의 구현이 다르게 작동했으며 일반 범주만 고려했습니다. 1.5.20부터는 구현이 플랫폼 전반에 걸쳐 통일되었고 두 속성을 모두 사용하여 문자 대소문자를 결정합니다:

kotlin
fun main() {
    val latinCapitalA = 'A' // has "Lu" general category
    val circledLatinCapitalA = 'Ⓐ' // has "Other_Uppercase" property
    println(latinCapitalA.isUpperCase() && circledLatinCapitalA.isUpperCase())
}