Kotlin 1.5.20의 새로운 기능
Kotlin 1.5.20에는 1.5.0의 새로운 기능에서 발견된 문제에 대한 수정 사항이 포함되어 있으며, 다양한 툴링 개선 사항도 포함되어 있습니다.
이러한 변경 사항에 대한 개요는 릴리스 블로그 게시물 및 다음 비디오에서 확인할 수 있습니다:
Kotlin/JVM
Kotlin 1.5.20은 JVM 플랫폼에서 다음과 같은 업데이트를 제공합니다:
- invokedynamic을 통한 문자열 연결
- JSpecify 널 가능성 어노테이션 지원
- Kotlin 및 Java 코드를 포함하는 모듈 내에서 Java의 Lombok으로 생성된 메서드 호출 지원
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 어노테이션을 처리하는 방법의 예시입니다:
// JavaClass.java
import org.jspecify.nullness.*;
@NullMarked
public class JavaClass {
public String notNullableString() { return ""; }
public @Nullable String nullableString() { return ""; }
}
// 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 코드는:
/**
* 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 헤더를 생성합니다:
/**
* 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 {
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
compilations.get("main").kotlinOptions.freeCompilerArgs += "-Xexport-kdoc"
}
}
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
파일에 다음 속성을 사용하십시오:
# 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.isLowerCase()/isUpperCase() 구현 통일.
Kotlin/Native 및 Kotlin/JS에서 Char.digitToInt()의 모든 유니코드 숫자 지원
Char.digitToInt()
는 문자가 나타내는 10진수 숫자의 값을 반환합니다. 1.5.20 이전에는 이 함수가 Kotlin/JVM에서만 모든 유니코드 숫자 문자를 지원했으며, Native 및 JS 플랫폼의 구현은 ASCII 숫자만 지원했습니다.
이제 Kotlin/Native와 Kotlin/JS 모두에서 모든 유니코드 숫자 문자에 대해 Char.digitToInt()
를 호출하고 해당 숫자 표현을 얻을 수 있습니다.
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_Category
와 Other_Uppercase
/Other_Lowercase
유니코드 속성을 모두 확인합니다.
1.5.20 이전에는 다른 플랫폼의 구현이 다르게 작동했으며 일반 범주만 고려했습니다. 1.5.20부터는 구현이 플랫폼 전반에 걸쳐 통일되었고 두 속성을 모두 사용하여 문자 대소문자를 결정합니다:
fun main() {
val latinCapitalA = 'A' // has "Lu" general category
val circledLatinCapitalA = 'Ⓐ' // has "Other_Uppercase" property
println(latinCapitalA.isUpperCase() && circledLatinCapitalA.isUpperCase())
}