본문 바로가기
Kotlin/What's new

[Kotlin 번역] What's new in Kotlin 1.9.0

by 노력남자 2023. 9. 17.
반응형

2023년 8월 23일

 

Kotlin 1.9.0 릴리스가 출시되었으며 JVM용 Kotlin K2 컴파일러가 이제 베타 버전으로 제공됩니다. 또한 다음은 주요 업데이트 중 일부입니다:

 

  • 새로운 Kotlin K2 컴파일러 업데이트
  • enum 클래스 values 함수의 안정적인 대체
  • 오픈 엔드 범위를 위한 안정된 ..< 연산자
  • 이름에 따라 regex 캡처 그룹을 얻는 데 사용하는 새로운 공통 함수
  • 상위 디렉토리를 만들기 위한 새로운 경로 유틸리티
  • Kotlin Multiplatform에서 Gradle 구성 캐시 미리보기
  • Kotlin Multiplatform에서 Android 대상 지원 변경
  • Kotlin/Native에서 사용자 지정 메모리 할당기 미리보기
  • Kotlin/Native에서 라이브러리 링크
  • Kotlin/Wasm에서 크기 관련 최적화

 

또한 이 업데이트에 대한 간단한 개요를 이 비디오에서 찾을 수 있습니다:

 

 


IDE 지원


Kotlin 1.9.0을 지원하는 Kotlin 플러그인은 다음과 같은 IDE에서 사용할 수 있습니다:

 


*Kotlin 1.9.0 플러그인은 Android Studio Giraffe (223) 및 Hedgehog (231)의 곧 출시될 버전에 포함될 예정입니다.

Kotlin 1.9.0 플러그인은 곧 출시될 IntelliJ IDEA 2023.2와 함께 포함될 예정입니다.

Kotlin 아티팩트와 종속성을 다운로드하려면 Gradle 설정을 Maven Central Repository를 사용하도록 구성하세요.

 

새로운 Kotlin K2 컴파일러 업데이트


JetBrains의 Kotlin 팀은 K2 컴파일러를 계속 안정화하고, 1.9.0 릴리스에서 더 많은 개선 사항을 도입했습니다. JVM용 Kotlin K2 컴파일러는 이제 베타 버전입니다.

또한 Kotlin/Native 및 멀티플랫폼 프로젝트에 대한 기본 지원이 추가되었습니다.


K2 컴파일러와 kapt 컴파일러 플러그인의 호환성


프로젝트에서 K2 컴파일러와 함께 kapt 플러그인을 사용할 수 있지만 일부 제한 사항이 있습니다. languageVersion을 2.0으로 설정하더라도 kapt 컴파일러 플러그인은 여전히 이전 컴파일러를 사용합니다.

프로젝트에서 languageVersion을 2.0으로 설정한 상태에서 kapt 컴파일러 플러그인을 실행하면 kapt는 자동으로 1.9로 전환하고 특정 버전 호환성 확인을 비활성화합니다. 이 동작은 다음 명령 인수를 포함하는 것과 동등합니다.

  • -Xskip-metadata-version-check
  • -Xskip-prerelease-check
  • -Xallow-unstable-dependencies


이러한 검사는 kapt 작업에 대해서만 비활성화됩니다. 다른 모든 컴파일 작업은 새 K2 컴파일러를 계속 사용합니다.

K2 컴파일러를 사용할 때 kapt와 관련하여 문제가 발생하면 문제 트래커에 보고하십시오.


프로젝트에서 K2 컴파일러를 시도해보세요


1.9.0부터 2.0 릴리스가 출시될 때까지 kotlin.experimental.tryK2=true Gradle 속성을 사용하여 K2 컴파일러를 쉽게 테스트할 수 있습니다. 또한 다음 명령을 실행할 수 있습니다.

./gradlew assemble -Pkotlin.experimental.tryK2=true


이 Gradle 속성은 자동으로 language version을 2.0으로 설정하고 빌드 보고서를 업데이트하여 K2 컴파일러를 사용하는 Kotlin 작업 수와 현재 컴파일러를 사용하는 Kotlin 작업 수를 비교합니다.

 

##### 'kotlin.experimental.tryK2' 결과 (Kotlin/Native 미포함) #####
:lib:compileKotlin: 2.0 언어 버전
:app:compileKotlin: 2.0 언어 버전
##### 100% (2/2) 작업이 Kotlin 2.0으로 컴파일되었습니다 #####


Gradle 빌드 보고서


Gradle 빌드 보고서에서 현재 또는 K2 컴파일러를 사용하여 코드를 컴파일한 것인지를 확인할 수 있습니다. Kotlin 1.9.0에서 Gradle 빌드 스캔에서 이 정보를 볼 수 있습니다.


또한 빌드 보고서에서 프로젝트에서 사용하는 Kotlin 버전을 확인할 수 있습니다.

Task info:
  Kotlin language version: 1.9


Gradle 8.0을 사용하는 경우 빌드 보고서에서 문제가 발생할 수 있으며 특히 Gradle 구성 캐싱이 활성화된 경우입니다. 이것은 알려진 문제이며 Gradle 8.1 이후에 수정되었습니다.


현재 K2 컴파일러의 제한 사항


Gradle 버전 8.3 미만을 사용하는 프로젝트에 영향을 미칠 수 있는 K2를 Gradle 프로젝트에 활성화하면 다음과 같은 제한 사항이 있을 수 있습니다.

  • buildSrc에서 소스 코드 컴파일
  • 포함된 빌드에서 Gradle 플러그인 컴파일
  • 8.3 미만의 Gradle 버전을 사용하는 프로젝트에서 다른 Gradle 플러그인 컴파일
  • Gradle 플러그인 종속성 빌드


위에서 언급한 문제 중 하나를 겪으면 다음 단계를 수행하여 해결할 수 있습니다.

  • buildSrc, 모든 Gradle 플러그인 및 그 종속성에 대한 언어 버전 설정:

kotlin {
    compilerOptions {
        languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9)
        apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9)
    }
}

 

  • 프로젝트의 Gradle 버전이 사용 가능해질 때 8.3로 업데이트합니다.


새로운 K2 컴파일러에 대한 피드백 남기기


우리는 여러분의 피드백을 환영합니다!

 

언어

 

Kotlin 1.9.0에서는 이전에 도입된 몇 가지 새로운 언어 기능을 안정화하고 있습니다:


enum 클래스 values 함수 안정적으로 대체


1.8.20에서 enum 클래스의 entries 속성이 실험적 기능으로 도입되었습니다. entries 속성은 합성 values() 함수에 대한 현대적이고 성능 향상된 대체물입니다. 1.9.0에서는 entries 속성이 안정화되었습니다.

values() 함수는 여전히 지원되지만 대신 entries 속성을 사용하는 것을 권장합니다.

enum class Color(val colorName: String, val rgb: String) {
    RED("Red", "#FF0000"),
    ORANGE("Orange", "#FF7F00"),
    YELLOW("Yellow", "#FFFF00")
}

fun findByRgb(rgb: String): Color? = Color.entries.find { it.rgb == rgb }


enum 클래스에 대한 entries 속성에 대한 자세한 내용은 Kotlin 1.8.20에서 무엇이 새로운지를 참조하세요.


대칭성을 갖는 데이터 클래스와 안정적인 데이터 객체


1.8.20에서 도입된 데이터 객체 선언은 이제 안정화되었습니다. 이것은 데이터 클래스와 대칭성을 유지하기 위해 도입된 함수인 toString(), equals(), hashCode()를 포함합니다.

이 기능은 밀봉된 계층 (밀봉된 클래스 또는 밀봉된 인터페이스 계층과 같이)에서 특히 유용합니다. 데이터 객체 선언은 데이터 클래스 선언과 함께 편리하게 사용할 수 있습니다. 이 예에서, EndOfFile를 일반 객체 대신 데이터 객체로 선언하면 toString() 함수를 수동으로 재정의하지 않고도 자동으로 가질 수 있습니다. 이것은 관련 데이터 클래스 정의와 대칭성을 유지하는 데 도움이 됩니다.

sealed interface ReadResult
data class Number(val number: Int) : ReadResult
data class Text(val text: String) : ReadResult
data object EndOfFile : ReadResult

fun main() {
    println(Number(7)) // Number(number=7)
    println(EndOfFile) // EndOfFile
}


자세한 내용은 Kotlin 1.8.20에서 무엇이 새로운지를 참조하세요.


인라인 값 클래스에서 본문이 있는 보조 생성자 지원


Kotlin 1.9.0부터는 인라인 값 클래스에서 본문이 있는 보조 생성자를 기본적으로 사용할 수 있습니다:

@JvmInline
value class Person(private val fullName: String) {
    // Kotlin 1.4.30부터 허용됨:
    init {
        check(fullName.isNotBlank()) {
            "Full name shouldn't be empty"
        }
    }
    // Kotlin 1.9.0부터는 기본적으로 허용됨:
    constructor(name: String, lastName: String) : this("$name $lastName") {
        check(lastName.isNotBlank()) {
            "Last name shouldn't be empty"
        }
    }
}


이전에 Kotlin은 인라인 클래스에서는 공개 기본 생성자만 허용했습니다. 결과적으로 기본 값을 캡슐화하거나 일부 제한된 값을 나타내는 인라인 클래스를 만드는 것이 불가능했습니다.

Kotlin이 발전함에 따라 이러한 문제가 해결되었습니다. Kotlin 1.4.30에서 init 블록에 대한 제한이 해제되었으며 그 후 Kotlin 1.8.20에서 본문이 있는 보조 생성자의 미리보기가 제공되었습니다. 이제 이러한 생성자는 기본적으로 사용할 수 있습니다. Kotlin 인라인 클래스 개발에 대한 자세한 내용은 이 KEEP에서 확인할 수 있습니다.

 

Kotlin/JVM


버전 1.9.0부터 컴파일러는 JVM 20에 해당하는 바이트코드 버전의 클래스를 생성할 수 있습니다. 또한 JvmDefault 어노테이션과 레거시 -Xjvm-default 모드의 폐기가 계속됩니다.


JvmDefault 어노테이션과 레거시 -Xjvm-default 모드의 폐기


Kotlin 1.5부터 JvmDefault 어노테이션의 사용이 폐기되었으며, 대신 더 최신의 -Xjvm-default 모드인 all 및 all-compatibility가 권장되었습니다. Kotlin 1.4에서 JvmDefaultWithoutCompatibility, Kotlin 1.6에서 JvmDefaultWithCompatibility가 도입되면서 이러한 모드는 DefaultImpls 클래스 생성에 대한 포괄적인 제어를 제공하여 이전 버전의 Kotlin 코드와의 원활한 호환성을 보장합니다.

따라서 Kotlin 1.9.0에서는 JvmDefault 어노테이션은 더 이상 의미가 없으며 폐기되어 오류가 발생합니다. 이 어노테이션은 나중에 Kotlin에서 제거될 것입니다.

 

Kotlin/Native


이 릴리스에서는 Kotlin/Native 메모리 매니저의 견고성과 성능을 향상시킬 수 있는 여러 개선 사항이 있습니다.


사용자 지정 메모리 할당기 미리보기


Kotlin 1.9.0은 사용자 지정 메모리 할당기의 미리보기를 도입합니다. 이 할당 시스템은 Kotlin/Native 메모리 매니저의 실행 시 성능을 향상시킵니다.

현재 Kotlin/Native에서 사용되는 객체 할당 시스템은 효율적인 가비지 컬렉션을 위한 기능을 갖추지 않은 일반적인 할당기를 사용합니다. 이를 보완하기 위해 가비지 컬렉터 (GC)가 이러한 객체를 병합하기 전에 모든 할당된 객체의 스레드 지역 연결 목록을 유지하며 이 목록은 스위핑 동안 반복할 수 있습니다. 이러한 접근 방식은 여러 가지 성능 문제를 동반합니다.

  • 스위핑 순서에는 메모리 지역성이 없으며 종종 흩어진 메모리 액세스 패턴으로 이어져 성능 문제가 발생할 수 있습니다.
  • 연결 목록은 각 객체마다 추가 메모리를 필요로 하므로 많은 작은 객체를 처리할 때 메모리 사용량이 증가합니다.
  • 할당된 객체의 단일 목록은 스위핑을 병렬로 수행하기 어렵게 하며, 이로 인해 mutator 스레드가 GC 스레드가 그것들을 수집하는 속도보다 빠르게 객체를 할당하는 경우 메모리 사용 문제가 발생할 수 있습니다.


이러한 문제를 해결하기 위해 Kotlin 1.9.0에서는 사용자 지정 할당기의 미리보기를 도입합니다. 이 할당기는 시스템 메모리를 페이지로 나누어 연속적인 순서로 독립적인 스위핑을 가능하게 합니다. 각 할당은 페이지 내의 메모리 블록이 되고 페이지는 블록 크기를 추적합니다. 다양한 할당 크기에 최적화된 다양한 페이지 유형이 있습니다. 메모리 블록의 연속된 배열은 할당된 모든 블록을 효율적으로 반복할 수 있도록 합니다.

스레드가 메모리를 할당할 때 할당 크기를 기반으로 적합한 페이지를 찾습니다. 스레드는 다른 크기 범주에 대한 여러 페이지를 유지합니다. 일반적으로 주어진 크기의 현재 페이지가 할당을 수용할 수 있습니다. 그렇지 않은 경우 스레드는 공유 할당 공간에서 다른 페이지를 요청합니다. 이 페이지는 이미 사용 가능할 수 있고, 스위핑이 필요할 수 있거나 먼저 생성해야 할 수 있습니다.

새 할당기는 동시에 여러 독립적인 할당 공간을 가질 수 있도록 하여 Kotlin 팀이 성능을 더 향상시키기 위해 다양한 페이지 레이아웃을 실험할 수 있게 합니다.

더 자세한 정보는 새 할당기의 설계에 대한 이 README를 참조하십시오.


활성화 방법


-Xallocator=custom 컴파일러 옵션을 추가하십시오.

kotlin {
    macosX64("native") {
        binaries.executable()

        compilations.configureEach {
            compilerOptions.configure {
                freeCompilerArgs.add("-Xallocator=custom")
            }
        }
    }
}


피드백 제공


사용자 지정 할당기를 개선하기 위해 YouTrack에서 피드백을 주시면 감사하겠습니다.

메인 스레드에서 Objective-C 또는 Swift 객체 해제 후크


Kotlin 1.9.0부터는 Objective-C 또는 Swift 객체 해제 후크가 해당 객체를 Kotlin으로 전달할 경우 메인 스레드에서 호출됩니다. 이전에 Kotlin/Native 메모리 매니저가 Objective-C 객체에 대한 참조를 처리하는 방식은 메모리 누수를 발생시킬 수 있었습니다. 새로운 동작은 메모리 매니저의 견고성을 향상시킬 것으로 기대됩니다.

Kotlin 코드에서 참조되는 Objective-C 객체가 있는 경우 (예: 인수로 전달되거나 함수에서 반환되거나 컬렉션에서 검색됨) Kotlin은 해당 Objective-C 객체에 대한 참조를 보유하는 자체 객체를 생성합니다. Kotlin 객체가 해제되면 Kotlin/Native 런타임은 해당 Objective-C 참조를 해제하는 objc_release 함수를 호출합니다.

이전에 Kotlin/Native 메모리 매니저는 특수한 GC 스레드에서 objc_release를 실행했습니다. 마지막 객체 참조이면 객체가 해제됩니다. Objective-C 객체에는 Objective-C의 dealloc 메서드 또는 Swift의 deinit 블록과 같이 특정 스레드에서 호출되기를 기대하는 사용자 정의 해제 후크가 있는 경우 문제가 발생할 수 있습니다.

Objective-C 객체가 일반적으로 메인 스레드에서 호출되길 기대하므로 Kotlin/Native 런타임은 이제 Objective-C 객체가 Kotlin에서 메인 스레드에서 Kotlin 피어 객체를 생성

한 경우에도 메인 스레드에서 objc_release를 호출합니다. 이것은 일반적인 UI 애플리케이션에 해당하는 경우에 작동합니다. 메인 대기열이 처리될 때만 작동하며 일반 대기열이나 다른 스레드에서 Objective-C 객체가 Kotlin에 전달되었거나 메인이 아닌 스레드에서 전달된 경우에는 이전과 같이 특수한 GC 스레드에서 objc_release가 호출됩니다.


비활성화하는 방법


문제가 발생하는 경우 gradle.properties 파일에서 다음 옵션을 사용하여 이 동작을 비활성화할 수 있습니다.

kotlin.native.binary.objcDisposeOnMain=false


이러한 경우를 issue tracker에 보고해 주시기 바랍니다.


Kotlin/Native에서 상수 값을 액세스할 때 객체 초기화 없음


Kotlin 1.9.0부터는 Kotlin/Native 백엔드에서 const val 필드에 액세스할 때 객체를 초기화하지 않습니다.

object MyObject {
    init {
        println("side effect!")
    }

    const val y = 1
}

fun main() {
    println(MyObject.y) // 초기화 없음
    val x = MyObject    // 초기화 발생
    println(x.y)
}


이 동작은 이제 Kotlin/JVM과 일치하며 구현이 Java와 일관되며 이러한 경우 객체를 초기화하지 않습니다. 이러한 변경으로 인해 Kotlin/Native 프로젝트에서 성능 향상을 기대할 수 있습니다.


Kotlin/Native에서 iOS 시뮬레이터 테스트의 독립 모드 구성 가능


기본적으로 Kotlin/Native의 iOS 시뮬레이터 테스트를 실행할 때는 수동으로 시뮬레이터 부팅 및 종료를 피하기 위해 --standalone 플래그가 사용됩니다. 1.9.0에서는 Gradle 작업에서 standalone 속성을 통해이 플래그를 사용 여부를 구성할 수 있습니다. 기본적으로 --standalone 플래그가 사용되므로 standalone 모드가 활성화됩니다.

build.gradle.kts 파일에서 standalone 모드를 비활성화하는 예제입니다.

tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest>().configureEach {
    standalone.set(false)
}


standalone 모드를 비활성화하는 경우 시뮬레이터를 수동으로 부팅해야 합니다. CLI에서 시뮬레이터를 부팅하려면 다음 명령을 사용할 수 있습니다.

/usr/bin/xcrun simctl boot <DeviceId>


Kotlin/Native에서 라이브러리 연결


Kotlin 1.9.0부터는 Kotlin/Native 컴파일러가 Kotlin/JVM과 동일한 방식으로 Kotlin 라이브러리의 연결 문제를 처리합니다. 한 써드파티 Kotlin 라이브러리의 작성자가 다른 써드파티 Kotlin 라이브러리에서 실험적인 API에서 호환되지 않는 변경을 수행하는 경우 이러한 문제가 발생할 수 있습니다.

이제 써드파티 Kotlin 라이브러리 간의 연결 문제로 인해 컴파일 중에 빌드가 실패하지 않습니다. 대신 이러한 오류는 JVM과 정확히 동일한 방식으로 실행 시간에만 발생합니다.

Kotlin/Native 컴파일러는 라이브러리 연결 문제를 감지할 때마다 경고를 보고합니다. 이러한 경고는 컴파일 로그에서 찾을 수 있습니다. 예를 들어 다음과 같이 컴파일 로그에서 이러한 경고를 찾을 수 있습니다.

No function found for symbol 'org.samples/MyRemovedClass.doSomething|3657632771909858561[0]'

Can not get instance of singleton 'MyEnumClass.REMOVED_ENTRY': No enum entry found for symbol 'org.samples/MyEnumClass.REMOVED_ENTRY|null[0]'

Function 'getMyRemovedClass' can not be called: Function uses unlinked class symbol 'org.samples/MyRemovedClass|null[0]'


프로젝트에서 이 동작을 더 구성하거나 비활성화할 수도 있습니다.

  • 컴파일 로그에서 이러한 경고를 표시하지 않으려면 -Xpartial-linkage-loglevel=INFO 컴파일러 옵션으로 경고를 억제하십시오.
  • 보고된 경고의 심각성을 컴파일 오류로 높일 수도 있으며 -Xpartial-linkage-loglevel=ERROR를 사용하십시오. 이 경우 컴파일이 실패하고 컴파일 로그에 모든 오류가 표시됩니다. 이 옵션을 사용하여 연결 문제를 더 자세히 조사하십시오.
  • 이 기능을 완전히 비활성화하려면 -Xpartial-linkage=disable 컴파일러 옵션을 사용하십시오. 문제가 발생하는 경우 issue tracker에 보고해 주시기 바랍니다.

 

kotlin {
    macosX64("native") {
        binaries.executable()

        compilations.configureEach {
            compilerOptions.configure {

                // 경고를 억제하려면:
                freeCompilerArgs.add("-Xpartial-linkage-loglevel=INFO")

                // 경고를 오류로 높이려면:
                freeCompilerArgs.add("-Xpartial-linkage-loglevel=ERROR")

                // 기능을 완전히 비활성화하려면:
               freeCompilerArgs.add("-Xpartial-linkage=disable")
            }
        }
    }
}

 

C 상호 운용용 암시적 정수 변환 컴파일러 옵션


C 상호 운용에서 암시적 정수 변환을 사용할 수 있도록하는 컴파일러 옵션을 도입했습니다. 이 기능은 아직 개선의 여지가 있으므로 의도하지 않은 사용을 방지하기 위해이 컴파일러 옵션을 도입했습니다. 이 코드 예제에서 암시적 정수 변환을 허용하면 options = 0이지만 options에는 unsigned type UInt가 있고 0은 signed입니다.

val today = NSDate()
val tomorrow = NSCalendar.currentCalendar.dateByAddingUnit(
    unit = NSCalendarUnitDay,
    value = 1,
    toDate = today,
    options = 0
)


이러한 암시적 변환을 Native 상호 운용 라이브러리와 함께 사용하려면 -XXLanguage:+ImplicitSignedToUnsignedIntegerConversion 컴파일러 옵션을 사용하십시오.

Gradle build.gradle.kts 파일에서 이를 구성하는 예제입니다.

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile>().configureEach {
    compilerOptions.freeCompilerArgs.addAll(
        "-XXLanguage:+ImplicitSignedToUnsignedIntegerConversion"
    )
}

 

Kotlin Multiplatform

 

Kotlin Multiplatform 1.9.0에서는 개발자 경험을 향상하기 위한 몇 가지 주요 업데이트를 받았습니다.


Android 대상 지원 변경 사항


Kotlin Multiplatform을 안정화하는 노력을 계속하고 있습니다. 중요한 단계 중 하나는 Android 대상을 지원하는 것입니다. 우리는 미래에 Google의 Android 팀이 Kotlin Multiplatform에서 Android를 지원하기 위한 자체 Gradle 플러그인을 제공할 것이라고 발표하게 되어 기쁩니다.

Google의 새로운 솔루션에 대한 길을 열기 위해 1.9.0에서 현재 Kotlin DSL의 android 블록의 이름을 변경하고 있습니다. 빌드 스크립트에서 android 블록의 모든 발생을 androidTarget으로 변경하십시오. 이것은 Google의 다가올 DSL을 위해 android 이름을 확보하기 위한 필요한 임시 변경입니다.

Google 플러그인은 멀티플랫폼 프로젝트에서 Android 작업을 하는 선호하는 방법이 될 것입니다. 준비되면 android 이름을 이전과 같이 사용할 수 있도록 필요한 이주 지침을 제공할 것입니다.


기본으로 활성화된 새로운 Android 소스 세트 레이아웃


Kotlin 1.9.0부터는 새로운 Android 소스 세트 레이아웃이 기본값으로 사용됩니다. 이는 이전에 디렉토리의 네이밍 스키마를 대체하는 레이아웃입니다. 새 레이아웃은 다음과 같은 이점이 있습니다.

 

  • 단순화된 유형 의미론 - 새 Android 소스 레이아웃은 서로 다른 유형의 소스 세트를 구분하는 데 도움이 되는 명확하고 일관된 네이밍 컨벤션을 제공합니다.
  • 개선된 소스 디렉토리 레이아웃 - 새 레이아웃을 통해 소스 디렉토리 배열이 더 일관성 있게 되어 코드를 조직하고 소스 파일을 찾기가 더 쉬워집니다.
  • Gradle 구성에 대한 명확한 네이밍 스키마 - 스키마는 이제 KotlinSourceSets 및 AndroidSourceSets에서 더 일관적이고 예측 가능하게 됩니다.


새 레이아웃은 Android Gradle 플러그인 버전 7.0 이상에서 필요하며 Android Studio 2022.3 이상에서 지원됩니다. build.gradle(.kts) 파일에서 필요한 변경 사항을 수행하기 위한 마이그레이션 가이드를 참조하십시오.


Gradle 구성 캐시 미리보기


Kotlin 1.9.0은 멀티플랫폼 라이브러리에서 Gradle 구성 캐시를 지원합니다. 라이브러리 작성자인 경우 개선된 빌드 성능을 누릴 수 있습니다.

Gradle 구성 캐시는 구성 단계의 결과를 다시 사용하여 빌드 프로세스를 가속화합니다. 이 기능은 Gradle 8.1부터 Stable 상태가 되었습니다. 이를 활성화하려면 Gradle 문서에 나와 있는 지침을 따르십시오.

Kotlin Multiplatform 플러그인은 아직 Xcode 통합 작업이나 Kotlin CocoaPods Gradle 플러그인과 함께 Gradle 구성 캐시를 지원하지 않습니다. 이러한 기능은 향후 Kotlin 릴리스에서 추가할 예정입니다.

 

Kotlin/Wasm

 

Kotlin 팀은 계속해서 새로운 Kotlin/Wasm 대상을 실험하고 있습니다. 이 릴리스에서는 JavaScript 상호 운용성 업데이트와 함께 성능 및 크기 관련 최적화가 여러 가지 소개되었습니다.

 

크기 관련 최적화


Kotlin 1.9.0에서는 WebAssembly (Wasm) 프로젝트에 대한 큰 크기 개선 사항이 도입되었습니다. 두 개의 "Hello World" 프로젝트를 비교할 때, Kotlin 1.9.0에서의 Wasm 코드 크기는 Kotlin 1.8.20에서의 것보다 10 배 이상 작아졌습니다.

 


이러한 크기 최적화는 Kotlin 코드를 사용하여 Wasm 플랫폼을 대상으로 할 때 더 효율적인 리소스 활용과 개선된 성능을 제공합니다.


JavaScript 상호 운용성 업데이트


이 Kotlin 업데이트는 Kotlin/Wasm의 Kotlin과 JavaScript 간 상호 운용성에 변경 사항을 도입합니다. Kotlin/Wasm은 실험적인 기능이므로 상호 운용성에 일부 제한 사항이 적용됩니다.


Dynamic 타입의 제한


버전 1.9.0부터 Kotlin은 Kotlin/Wasm에서 Dynamic 타입의 사용을 더 이상 지원하지 않습니다. 이것은 이제 새로운 범용 JsAny 타입을 선호합니다. 이것은 JavaScript 상호 운용성을 용이하게 합니다.

자세한 내용은 Kotlin/Wasm과 JavaScript 간 상호 운용성 문서를 참조하십시오.


비-external 타입의 제한


Kotlin/Wasm은 JavaScript로 값의 전달 및 반환시 특정 Kotlin 정적 타입에 대한 변환을 지원합니다. 이러한 지원되는 타입은 다음과 같습니다.

  • 기본 자료형, 예를 들어 부호 있는 숫자, Boolean 및 Char.
  • String.
  • 함수 타입.


기타 타입은 JavaScript와 Kotlin 서브 타이핑 사이에 불일치를 일으키는 불투명한 참조로 전달되었습니다.

이 문제를 해결하기 위해 Kotlin은 JavaScript 상호 운용성을 잘 지원하는 일련의 타입으로 제한합니다. Kotlin 1.9.0부터 Kotlin/Wasm JavaScript 상호 운용성에서는 external, 기본 자료형, 문자열 및 함수 타입만 지원됩니다. 또한 JavaScript 상호 운용성에서 Kotlin/Wasm 객체에 대한 핸들을 나타내는 별도의 명시적 타입인 JsReference가 도입되었습니다.

자세한 내용은 Kotlin/Wasm과 JavaScript 간 상호 운용성 문서를 참조하십시오.


Kotlin Playground에서의 Kotlin/Wasm


Kotlin Playground은 Kotlin/Wasm 대상을 지원합니다. Kotlin/Wasm을 대상으로 하는 Kotlin 코드를 작성, 실행 및 공유할 수 있습니다. 확인해보세요!

Kotlin/Wasm을 사용하려면 브라우저에서 실험 기능을 활성화해야 합니다.

이러한 기능을 활성화하는 방법에 대한 자세한 내용을 알아보세요.

 

import kotlin.time.*
import kotlin.time.measureTime

fun main() {
    println("Hello from Kotlin/Wasm!")
    computeAck(3, 10)
}

tailrec fun ack(m: Int, n: Int): Int = when {
    m == 0 -> n + 1
    n == 0 -> ack(m - 1, 1)
    else -> ack(m - 1, ack(m, n - 1))
}

fun computeAck(m: Int, n: Int) {
    var res = 0
    val t = measureTime {
        res = ack(m, n)
    }
    println()
    println("ack($m, $n) = ${res}")
    println("duration: ${t.inWholeNanoseconds / 1e6} ms")
}

 

Kotlin/JS

 

Kotlin/JS에 대한 업데이트가 포함된 이 릴리스에는 이전 Kotlin/JS 컴파일러의 제거, Kotlin/JS Gradle 플러그인의 폐기 및 ES6에 대한 실험적 지원이 포함되어 있습니다.

이전 Kotlin/JS 컴파일러의 제거


Kotlin 1.8.0에서 IR 기반 백엔드가 안정화되었음을 발표하였습니다. 이후 컴파일러를 지정하지 않으면 오류가 발생하고 이전 컴파일러를 사용하면 경고가 발생합니다.

Kotlin 1.9.0에서 이전 백엔드를 사용하면 오류가 발생합니다. 이전 컴파일러에서 IR 컴파일러로 마이그레이션하려면 마이그레이션 가이드를 따르십시오.


Kotlin/JS Gradle 플러그인의 폐기


Kotlin 1.9.0부터 kotlin-js Gradle 플러그인은 폐기되었습니다. kotlin-multiplatform Gradle 플러그인을 사용하여 js() 대상을 사용하는 것을 권장합니다.

Kotlin/JS Gradle 플러그인의 기능은 본질적으로 kotlin-multiplatform 플러그인과 중복되며 내부에서 동일한 구현을 공유합니다. 이 중복으로 인해 혼란이 생기고 Kotlin 팀에게 유지 관리 부담이 더 커졌습니다.

마이그레이션 지침에 대한 자세한 내용은 Kotlin Multiplatform 호환성 가이드를 참조하십시오. 가이드에서 다루지 않는 문제를 발견하면 이슈 트래커에 보고해 주세요.


external enum의 폐기


Kotlin 1.9.0에서는 외부 열거형(external enums) 사용이 폐기됩니다. 외부 열거형은 entries와 같은 정적 열거형 멤버를 지원하지 못하는 문제로 인해 폐기됩니다. 대신 다음과 같이 외부 sealed 클래스와 object 하위 클래스를 사용하는 것을 권장합니다.

 

// Before
external enum class ExternalEnum { A, B }

// After
external sealed class ExternalEnum {
    object A: ExternalEnum
    object B: ExternalEnum
}


외부 sealed 클래스와 object 하위 클래스를 사용하면 기본 메서드와 관련된 문제를 피하면서 외부 열거형과 유사한 기능을 얻을 수 있습니다.

Kotlin 1.9.0부터 외부 열거형 사용이 폐기될 예정이며, 호환성 및 향후 유지 보수를 위해 권장된 외부 sealed 클래스 구현을 사용하도록 권장합니다.


ES6 클래스 및 모듈의 실험적 지원


이 릴리스에서는 ES6 모듈과 ES6 클래스 생성의 실험적 지원이 소개되었습니다.

- 모듈은 코드베이스를 단순화하고 유지 관리를 향상시키는 방법을 제공합니다.
- 클래스는 객체 지향 프로그래밍(OOP) 원칙을 포함하여 더 깨끗하고 직관적인 코드를 작성할 수 있도록 합니다.

이러한 기능을 활성화하려면 build.gradle.kts 파일을 다음과 같이 업데이트하십시오:

// build.gradle.kts
kotlin {
    js(IR) {
        useEsModules() // ES6 모듈을 활성화합니다.
        browser()
    }
}

// ES6 클래스 생성을 활성화합니다.
tasks.withType<KotlinJsCompile>().configureEach {
    kotlinOptions {
        useEsClasses = true
    }
}


ECMAScript 2015 (ES6)에 대한 자세한 내용은 공식 문서를 참조하십시오.

 

JS 프로덕션 분배의 기본 대상 변경


Kotlin 1.9.0 이전에는 분배 대상 디렉터리가 build/distributions이었습니다. 그러나 이것은 Gradle 아카이브의 공통 디렉터리입니다. 이 문제를 해결하기 위해 Kotlin 1.9.0에서는 기본 분배 대상 디렉터리를 build/dist/<targetName>/<binaryName>로 변경하였습니다.

예를 들어, productionExecutable은 build/distributions에 있었습니다. Kotlin 1.9.0에서는 build/dist/js/productionExecutable에 있습니다.

이러한 빌드 결과를 사용하는 파이프라인이 있다면 디렉터리를 업데이트해야 합니다.


stdlib-js에서 org.w3c 선언 추출


Kotlin 1.9.0부터 stdlib-js에는 더 이상 org.w3c 선언이 포함되지 않습니다. 대신 이러한 선언은 별도의 Gradle 종속성으로 이동되었습니다. build.gradle.kts 파일에 Kotlin Multiplatform Gradle 플러그인을 추가하면 이러한 선언이 자동으로 프로젝트에 포함됩니다. 표준 라이브러리와 유사하게 처리됩니다.

수동 작업이나 마이그레이션 작업이 필요하지 않습니다. 필요한 조치는 자동으로 처리됩니다.

 

Gradle

 

Kotlin 1.9.0은 새로운 Gradle 컴파일러 옵션과 더 많은 기능을 제공합니다:


classpath 속성 제거


Kotlin 1.7.0에서는 KotlinCompile 작업의 classpath 속성에 대한 사용을 중단하는 시작을 발표했습니다. Kotlin 1.8.0에서 중지 수준이 ERROR로 변경되었습니다. 이 릴리스에서는 classpath 속성을 완전히 제거했습니다. 이제 모든 컴파일 작업은 컴파일에 필요한 라이브러리 목록에 대한 libraries 입력을 사용해야 합니다.


새로운 컴파일러 옵션


Kotlin Gradle 플러그인은 이제 새로운 API에 대한 사용자 정의 및 컴파일러의 점진적 모드를 활성화하는 데 사용할 수 있는 새로운 속성을 제공합니다.

  • 새 API에 대한 사용을 활성화하려면 optIn 속성을 사용하고 optIn.set(listOf(a, b, c))와 같이 문자열 목록을 전달할 수 있습니다.
  • 점진적 모드를 활성화하려면 progressiveMode.set(true)를 사용합니다.

 

Kotlin/JVM을 위한 프로젝트 수준 컴파일러 옵션


Kotlin 1.9.0부터 kotlin 구성 블록 내에서 새로운 compilerOptions 블록이 사용 가능합니다.

kotlin {
    compilerOptions {
        jvmTarget.set(JVM.Target_11)
    }
}


이를 통해 컴파일러 옵션을 구성하는 것이 훨씬 쉬워집니다. 그러나 중요한 몇 가지 세부 사항을 주의해야 합니다.

  • 이 구성은 프로젝트 수준에서만 작동합니다.
  • Android 플러그인의 경우이 블록은 다음과 동일한 개체를 구성합니다.

 

android {
    kotlinOptions {}
}

 

  • android.kotlinOptions 및 kotlin.compilerOptions 구성 블록은 서로 덮어쓰며 빌드 파일의 마지막 (가장 낮은) 블록이 항상 적용됩니다.
  • 프로젝트 수준에서 moduleName이 구성된 경우 컴파일러에 전달될 때 값이 변경될 수 있습니다. 이는 주요 컴파일에 대해서는 해당하지 않지만 예를 들어 테스트 소스와 같은 다른 유형에 대해서는 Kotlin Gradle 플러그인이 _test 접미사를 추가할 수 있습니다.
  • tasks.withType<KotlinJvmCompile>().configureEach {} (또는 tasks.named<KotlinJvmCompile>("compileKotlin") {}를 사용한 경우 kotlin.compilerOptions 및 android.kotlinOptions를 모두 재정의합니다.


Kotlin/Native 모듈 이름을 위한 컴파일러 옵션


Kotlin/Native module-name 컴파일러 옵션은 이제 Kotlin Gradle 플러그인에서 쉽게 사용할 수 있습니다.

이 옵션은 컴파일 모듈의 이름을 지정하며 Objective-C에 내보내는 선언에 이름 접두사를 추가하는 데도 사용할 수 있습니다.

이제 Gradle 빌드 파일의 compilerOptions 블록에서 직접 모듈 이름을 설정할 수 있습니다.

tasks.named<org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile>("compileKotlinLinuxX64") {
    compilerOptions {
        moduleName.set("my-module-name")
    }
}


라이브러리용 별도의 컴파일러 플러그인


Kotlin 1.9.0은 공식 라이브러리를 위한 별도의 컴파일러 플러그인을 도입합니다. 이전에 컴파일러 플러그인은 해당하는 Gradle 플러그인에 내장되었습니다. 이로 인해 컴파일러 플러그인이 Gradle 빌드의 Kotlin 런타임 버전보다 높은 Kotlin 버전으로 컴파일되면 호환성 문제가 발생할 수 있었습니다.

이제 컴파일러 플러그인은 별도의 종속성으로 추가되므로 이전 Gradle 버전과의 호환성 문제가 더 이상 발생하지 않습니다. 이러한 새 접근 방식의 주요 장점 중 하나는 새 컴파일러 플러그인을 Bazel과 같은 다른 빌드 시스템에서 사용할 수 있다는 것입니다.

다음은 Maven Central에 게시된 새로운 컴파일러 플러그인 목록입니다:

  • kotlin-atomicfu-compiler-plugin
  • kotlin-allopen-compiler-plugin
  • kotlin-lombok-compiler-plugin
  • kotlin-noarg-compiler-plugin
  • kotlin-sam-with-receiver-compiler-plugin
  • kotlinx-serialization-compiler-plugin


각 플러그인에는 해당 플러그인과 함께 사용되는 kotlin-compiler-embeddable 아티팩트를 다루기 위한 kotlin-allopen-compiler-plugin-embeddable과 같은 -embeddable 대응편이 있습니다. 이것은 스크립팅 아티팩트의 기본 옵션입니다.

Gradle은 이러한 플러그인을 컴파일러 인수로 추가합니다. 기존 프로젝트에 대해 어떤 변경도 필요하지 않습니다.


최소 지원 버전 증가


Kotlin 1.9.0부터 최소 지원되는 Android Gradle 플러그인 버전은 4.2.2입니다.

Kotlin Gradle 플러그인의 Gradle 버전 호환성을 문서에서 확인할 수 있습니다.


Gradle에서 kapt가 즉시 작업 생성을 유발하지 않음


1.9.0 이전에는 kapt 컴파일러 플러그인이 Kotlin 컴파일 작업의 구성된 인스턴스를 요청하여 즉시 작업 생성을 유발했습니다. Kotlin 1.9.0에서는 이 동작이 수정되었습니다. 기본 build.gradle.kts 파일 구성을 사용하는 경우 설정이 영향받지 않습니다.

사용자 지정 구성을 사용하는 경우 설정이 영향을 받습니다. 예를 들어 build.gradle.kts 스크립트가 KotlinJvmCompile 작업에 대한 다음 구성을 가지고 있는 경우:

tasks.named<KotlinJvmCompile>("compileKotlin") { // 사용자 지정 구성 }


이 경우 KaptGenerateStubs 작업에도 동일한 수정이 포함되어야 합니다:

tasks.named<KaptGenerateStubs>("kaptGenerateStubs") { // 사용자 지정 구성 }


더 많은 정보는 YouTrack 티켓을 참조하십시오.


JVM 대상 검증 모드의 프로그래밍 구성


Kotlin 1.9.0 이전에 Kotlin과 Java 간의 JVM 대상 비호환성 감지를 조정하는 방법은 하나뿐이었습니다. gradle.properties에서 kotlin.jvm.target.validation.mode=ERROR를 설정해야 했습니다. 

 

이제 build.gradle.kts 파일에서 작업 수준에서도 구성할 수 있습니다.

tasks.named<org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile>("compileKotlin") {
    jvmTargetValidationMode.set(org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.WARNING)
}

 

표준 라이브러리

 

Kotlin 1.9.0의 표준 라이브러리에는 몇 가지 훌륭한 개선 사항이 있습니다:


안정된 ..< 연산자


Kotlin 1.7.20에서 도입된 개방 범위를 위한 새 ..< 연산자가 Kotlin 1.8.0에서 안정화되었습니다. 1.9.0에서는 개방 범위와 함께 작업하는 표준 라이브러리 API도 안정화되었습니다.

새 ..< 연산자는 개방 범위가 선언될 때 더 이해하기 쉽다는 연구 결과를 보여줍니다. until 중위 함수를 사용하면 상한값이 포함된 것으로 가정하기 쉽지만, ..< 연산자를 사용하면 이런 오해를 방지할 수 있습니다.

다음은 until 함수를 사용한 예제입니다:

fun main() {
    for (number in 2 until 10) {
        if (number % 2 == 0) {
            print("$number ")
        }
    }
    // 2 4 6 8
}


여기서 ..< 연산자를 사용한 예제입니다:

fun main() {
    for (number in 2..<10) {
        if (number % 2 == 0) {
            print("$number ")
        }
    }
    // 2 4 6 8
}


IntelliJ IDEA 버전 2023.1.1부터는 ..< 연산자를 사용할 수 있는 경우를 강조 표시하는 새로운 코드 검사 기능이 제공됩니다.

이 연산자로 무엇을 할 수 있는지 자세한 내용은 Kotlin 1.7.20에서 어떤 새로운 기능이 있는지를 참조하십시오.


안정된 시간 API


1.3.50부터 새로운 시간 측정 API를 미리 보여 주었습니다. API의 duration 부분은 1.6.0에서 안정화되었습니다. 1.9.0에서는 나머지 시간 측정 API가 안정화되었습니다.

이전 시간 API는 사용하기 어려운 measureTimeMillis 및 measureNanoTime 함수를 제공했습니다. 이러한 함수가 각각 다른 단위로 시간을 측정한다는 것은 분명하지만, measureTimeMillis는 시간을 측정할 때 벽 시계를 사용하고, measureNanoTime은 단조 시간 소스를 사용한다는 것은 분명하지 않았습니다. 새로운 시간 API는 이와 다른 문제를 해결하여 API를 더 사용자 친화적으로 만듭니다.

새로운 시간 API를 사용하여 다음을 수행할 수 있습니다:

  • 원하는 시간 단위로 명령 코드를 실행하는 데 걸리는 시간을 측정합니다.
  • 시간의 특정 시점을 표시합니다.
  • 두 시간 간의 차이를 비교하고 차이를 찾습니다.
  • 특정 시점으로부터 경과한 시간을 확인합니다.
  • 현재 시간이 특정 시점을 지났는지 확인합니다.

 

코드 실행 시간 측정하기

 

코드 블록을 실행하는 데 걸리는 시간을 측정하려면 measureTime 인라인 함수를 사용하십시오.

코드 블록을 실행하는 데 걸리는 시간을 측정하고 코드 블록의 결과를 반환하려면 measureTimedValue 인라인 함수를 사용하십시오.

기본적으로 이러한 함수 모두 단조 시간 소스를 사용합니다. 그러나 경과된 실시간 소스를 사용하려면 사용자 지정하려면 사용할 수 있습니다. 예를 들어 Android에서 기본 시간 소스인 System.nanoTime()는 기기가 활성 상태일 때만 시간을 계산합니다. 기기가 깊은 절전 모드로 들어가면 시간을 추적하지 못합니다. 기기가 깊은 절전 모드에서 시간을 추적하려면 SystemClock.elapsedRealtimeNanos()를 사용하는 시간 소스를 만들 수 있습니다.

object RealtimeMonotonicTimeSource : AbstractLongTimeSource(DurationUnit.NANOSECONDS) {
    override fun read(): Long = SystemClock.elapsedRealtimeNanos()
}


시간을 표시하고 시간 간의 차이를 측정하기


특정 시간을 표시하려면 TimeSource 인터페이스를 사용하고 markNow() 함수를 사용하여 TimeMark를 만듭니다. 동일한 시간 소스에서 TimeMark 간의 차이를 측정하려면 뺄셈 연산자 (-)를 사용하십시오.

import kotlin.time.*

fun main() {
    val timeSource = TimeSource.Monotonic
    val mark1 = timeSource.markNow()
    Thread.sleep(500) // 0.5초 대기
    val mark2 = timeSource.markNow()

    repeat(4) { n ->
        val mark3 = timeSource.markNow()
        val elapsed1 = mark3 - mark1
        val elapsed2 = mark3 - mark2

        println("Measurement 1.${n + 1}: elapsed1=$elapsed1

, elapsed2=$elapsed2, diff=${elapsed1 - elapsed2}")
    }
    // TimeMark 간에 비교할 수도 있습니다.
    println(mark2 > mark1) // 이것은 mark2가 mark1보다 뒤에 캡처되었기 때문에 true입니다.
}


마감 기한이 지났는지 또는 시간 초과가 발생했는지 확인하려면 hasPassedNow() 및 hasNotPassedNow() 확장 함수를 사용하십니다.

import kotlin.time.*
import kotlin.time.Duration.Companion.seconds

fun main() {
    val timeSource = TimeSource.Monotonic
    val mark1 = timeSource.markNow()
    val fiveSeconds: Duration = 5.seconds
    val mark2 = mark1 + fiveSeconds

    // 5초가 아직 지나지 않았습니다.
    println(mark2.hasPassedNow())
    // false

    // 6초를 기다립니다.
    Thread.sleep(6000)
    println(mark2.hasPassedNow())
    // true
}


Kotlin/Native 표준 라이브러리의 안정화


Kotlin/Native용 표준 라이브러리가 계속 성장함에 따라 저희는 높은 표준을 충족하는지 확인하기 위해 완전한 검토가 필요하다고 판단했습니다. 이에 따라 각 공개 시그니처를 주의 깊게 검토하였습니다. 

 

  • 각 시그니처에 대해 고유한 목적이 있는지
  • 다른 Kotlin API와 일관성이 있는지
  • JVM용 상응물과 유사한 동작을 하는지
  • 미래를 대비하는지를 고려하였습니다.


이러한 고려 사항을 바탕으로 다음 중 하나를 결정하였습니다.

  • 안정화됨
  • 실험적
  • 비공개로 표시
  • 동작 수정
  • 다른 위치로 이동
  • 폐기
  • 사용하지 않음으로 표시


기존 시그니처가 다른 패키지로 이동된 경우, 

 

  • 해당 시그니처는 여전히 원래 패키지에 존재하지만 경고 수준이 WARNING로 설정되어 있으며 IntelliJ IDEA는 코드 검사 시 교체를 자동으로 제안합니다.
  • 폐기된 경우, 경고 수준이 WARNING로 설정되어 있습니다.
  • 사용하지 않음으로 표시된 경우 계속 사용할 수 있지만 나중에 대체될 것입니다.

 

모든 결과를 여기에 나열하지는 않겠지만 몇 가지 주요 사항은 다음과 같습니다:

  • Atomics API가 안정화되었습니다.
  • kotlinx.cinterop를 실험적으로 표시하고 패키지 사용에 대한 다른 옵트인을 필요로 합니다. 자세한 내용은 명시적 C-상호 운용성 안정성 보증을 참조하십시오.
  • Worker 클래스 및 관련 API를 사용하지 않도록 표시하였습니다.
  • BitSet 클래스를 사용하지 않도록 표시하였습니다.
  • kotlin.native.internal 패키지의 모든 공개 API를 비공개로 표시하거나 다른 패키지로 이동하였습니다.


명시적 C-상호 운용성 안정성 보증


API의 품질을 유지하기 위해 kotlinx.cinterop을 실험적으로 표시하기로 결정하였습니다. kotlinx.cinterop은 철저히 검증되고 테스트되었지만 아직 충분히 안정화되지 않아 안정화되기 전까지 특정 프로젝트의 특정 영역에 사용하도록 권장합니다. 이렇게 하면 이 API를 안정화하기 시작할 때 마이그레이션을 더 쉽게 할 수 있습니다.

포인터와 같은 C 스타일의 외부 API를 사용하려면 @OptIn(ExperimentalForeignApi)로 옵트인해야 하며, 그렇지 않으면 코드가 컴파일되지 않습니다.

Objective-C/Swift 상호 운용성을 다루는 나머지 kotlinx.cinterop을 사용하려면 @OptIn(BetaInteropApi)로 옵트인해야 합니다. 이 옵트인 없이 이 API를 사용하려고 하면 코드가 컴파일되지만 어떤 동작을 기대할 수 있는지에 대한 명확한 설명을 제공하는 경고가 발생합니다.

이러한 어노테이션에 대한 자세한 내용은 Annotations.kt의 소스 코드를 참조하십시오.

이 리뷰의 일환으로 수행한 모든 변경 사항에 대한 자세한 내용은 YouTrack 티켓을 참조하십시오.


안정된 @Volatile 어노테이션


변수 프로퍼티를 @Volatile로 주석 처리하면 해당 백킹 필드는 이 필드에 대한 모든 읽기 또는 쓰기가 원자적으로 표시되고 쓰기는 항상 다른 스레드에서 볼 수 있도록 표시됩니다.

1.8.20 이전에는 kotlin.jvm.Volatile 어노테이션이 공통 표준 라이브러리에서 사용 가능했지만 JVM에서만 효과가 있었습니다. 다른 플랫폼에서 사용하면 무시되어 오류가 발생했습니다.

1.8.20에서는 실험적인 공통 어노테이션 kotlin.concurrent.Volatile을 도입하여 JVM 및 Kotlin/Native에서 미리보기로 사용할 수 있었습니다.

1.9.0에서 kotlin.concurrent.Volatile이 안정화되었습니다. 다중 플랫폼 프로젝트에서 kotlin.jvm.Volatile을 사용하고 있다면 kotlin.concurrent.Volatile로 마이그레이션하는 것을 권장합니다.

 

이름으로 정규 표현식 캡처 그룹 얻는 새로운 공통 함수


1.9.0 이전에는 각 플랫폼에서 정규 표현식 일치에서 이름으로 캡처 그룹을 가져오기 위한 확장 기능이 있었지만 공통 함수가 없었습니다. Kotlin 1.8.0 이전에는 일반 함수를 가질 수 없었습니다. 왜냐하면 표준 라이브러리가 아직 JVM 대상 1.6 및 1.7을 지원하기 때문입니다.

Kotlin 1.8.0부터 표준 라이브러리는 JVM 대상 1.8로 컴파일됩니다. 그래서 1.9.0에서는 정규 표현식 일치의 캡처 그룹에서 이름으로 일치된 값을 가져오기 위한 공통 groups 함수가 도입되었습니다. 이 함수는 특정 캡처 그룹에 속하는 정규 표현식 일치의 결과에 액세스하려는 경우 유용합니다.

다음은 세 개의 캡처 그룹(city, state 및 areaCode)을 포함하는 정규 표현식을 사용하여 일치된 값을 가져오는 예제입니다:

fun main() {
    val regex = """\b(?<city>[A-Za-z\s]+),\s(?<state>[A-Z]{2}):\s(?<areaCode>[0-9]{3})\b""".toRegex()
    val input = "Coordinates: Austin, TX: 123"

    val match = regex.find(input)!!
    println(match.groups["city"]?.value)
    // Austin
    println(match.groups["state"]?.value)
    // TX
    println(match.groups["areaCode"]?.value)
    // 123
}


부모 디렉터리 생성하는 새로운 경로 유틸리티


1.9.0에서는 새로운 createParentDirectories() 확장 함수가 도입되었습니다. 이 함수를 사용하면 모든 필요한 상위 디렉터리가 포함된 새 파일을 생성할 수 있습니다. createParentDirectories()에 파일 경로를 제공하면 부모 디렉터리가 이미 존재하는지 확인하고, 존재하지 않으면 자동으로 생성합니다.

파일 복사 작업을 수행할 때 createParentDirectories()는 특히 유용합니다. 예를 들어, copyToRecursively() 함수와 결합하여 사용할 수 있습니다:

sourcePath.copyToRecursively(
   destinationPath.createParentDirectories(),
   followLinks = false
)


새로운 HexFormat 클래스: 16진수 형식화 및 구문 분석


새로운 HexFormat 클래스와 관련된 확장 함수는 실험적인 기능으로 제공되며, 이를 사용하려면 @OptIn(ExperimentalStdlibApi::class) 또는 컴파일러 인수 -opt-in=kotlin.ExperimentalStdlibApi을 사용할 수 있습니다.

1.9.0에서 HexFormat 클래스와 관련된 확장 함수는 수치 값을 16진수 문자열로 변환하고 16진수 문자열과 ByteArray 또는 다른 숫자 유형(Int, Short, Long) 간 변환을 할 수 있는 실험적인 기능으로 제공됩니다.

예를 들어:

println(93.toHexString()) // "0000005d"


HexFormat 클래스에는 HexFormat{} 빌더를 사용하여 구성할 수 있는 형식 옵션이 포함되어 있습니다.

ByteArray를 다룰 때 다음과 같은 프로퍼티로 구성할 수 있는 옵션이 있습니다:

 


예를 들어:

val macAddress = "001b638445e6".hexToByteArray()

// HexFormat{} 빌더를 사용하여 16진수 문자열을 콜론으로 구분합니다
println(macAddress.toHexString(HexFormat { bytes.byteSeparator = ":" }))
// "00:1b:63:84:45:e6"

// HexFormat{} 빌더를 사용하여 다음을 수행합니다:
// * 16진수 문자열을 대문자로 만듭니다.
// * 바이트를 쌍으로 그룹화합니다.
// * 마침표로 구분합니다.
val threeGroupFormat = HexFormat { upperCase = true; bytes.bytesPerGroup = 2; bytes.groupSeparator = "." }

println(macAddress.toHexString(threeGroupFormat))
// "001B.6384.45E6"


숫자 유형을 사용할 때 다음과 같은 프로퍼티로 구성할 수 있는 옵션이 있습니다:

 


예를 들어:

// HexFormat

{} 빌더를 사용하여 "0x" 접두사를 가진 16진수를 구문 분석합니다.
println("0x3a".hexToInt(HexFormat { number.prefix = "0x" })) // "58"

 

문서 업데이트

 

Kotlin 문서에 중요한 업데이트 사항이 있습니다:


Kotlin 1.9.0 설치


IDE 버전 확인


IntelliJ IDEA 2022.3.3 및 2023.1.1은 Kotlin 플러그인을 자동으로 1.9.0 버전으로 업데이트하는 것을 제안합니다. IntelliJ IDEA 2023.2는 Kotlin 1.9.0 플러그인을 포함할 것입니다.

Android Studio Giraffe (223) 및 Hedgehog (231)은 곧 출시될 릴리스에서 Kotlin 1.9.0을 지원할 예정입니다.

새로운 명령줄 컴파일러는 GitHub 릴리스 페이지에서 다운로드할 수 있습니다.


Gradle 설정 구성


Kotlin 아티팩트와 종속성을 다운로드하려면 settings.gradle(.kts) 파일을 업데이트하여 Maven Central 저장소를 사용하도록 설정하세요:

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}


저장소가 지정되지 않은 경우 Gradle은 Kotlin 아티팩트와 관련된 문제를 일으킬 수 있는 sunset JCenter 저장소를 사용합니다.


Kotlin 1.9.0 호환성 가이드


Kotlin 1.9.0은 기능 릴리스이며, 이전 버전의 언어에 작성된 코드와 호환되지 않을 수 있는 변경 사항을 가져올 수 있습니다. 이러한 변경 사항의 자세한 목록은 Kotlin 1.9.0 호환성 가이드에서 찾을 수 있습니다.

 

원문

 

https://kotlinlang.org/docs/whatsnew19.html#compatibility-guide-for-kotlin-1-9-0

반응형

댓글