소요 시간: 약 10분

Kotlin의 주요 버전별 변경점을 정리합니다. 마이그레이션 시 참고할 핵심 변경사항과 팁을 제공합니다.

핵심 요약
  • Kotlin 2.0: K2 컴파일러 안정화 — 최대 2배 빠른 컴파일 속도
  • Kotlin 2.0: data object 정식 지원
  • Kotlin 1.9: Enum.entries 추가 (.values() 대체)
  • Kotlin 1.7: 빌더 추론 개선, by lazy 스레드 모드 개선
  • Kotlin 1.5: value class (인라인 클래스) 안정화, sealed interface 추가

Kotlin 버전 한눈에 보기#

버전주요 변경점JVM 최소 요구
1.4.xSAM 변환 개선, fun interfaceJVM 8
1.5.xvalue class, sealed interface, Result 개선JVM 8
1.6.xsealed class when 완전성 경고, Regex 개선JVM 8
1.7.xK1 컴파일러 개선, @OptIn 안정화JVM 8
1.8.xkotlin-reflect 경량화, Java 18-19 지원JVM 8
1.9.xEnum.entries, data object, 범위 함수 개선JVM 8
2.0.xK2 컴파일러 안정화, 스마트 캐스트 개선JVM 8
2.1.x가드 조건(when guard), Non-local break/continueJVM 8

Kotlin 2.0 — 핵심 변경점#

K2 컴파일러 안정화

K2는 Kotlin 컴파일러를 완전히 새로 작성한 프론트엔드입니다. Kotlin 2.0에서 Stable로 승격되었습니다.

항목변화
컴파일 속도평균 최대 2배 향상 (프로젝트 규모에 따라 다름)
타입 추론더 정확한 추론, 일부 오류 수정
IDE 분석IntelliJ 분석 엔진을 K2 기반으로 전환
플러그인 호환성기존 컴파일러 플러그인은 K2 API로 업데이트 필요
// 2.0에서 스마트 캐스트 개선 예시
class Container(val value: Any?) {
    fun printLength() {
        val v = value
        if (v is String) {
            println(v.length)   // 이전: 일부 케이스에서 스마트 캐스트 실패
                                // 2.0: 올바르게 스마트 캐스트
        }
    }
}

data object (2.0 정식)

object 선언에 data를 붙이면 toString()이 클래스 이름을 반환합니다. sealed 계층에서 값이 없는 케이스에 유용합니다.

sealed class ApiResult {
    data class Success(val body: String) : ApiResult()
    data class Error(val code: Int, val message: String) : ApiResult()
    data object Loading : ApiResult()     // toString() = "Loading"
    data object Empty : ApiResult()       // toString() = "Empty"
}

println(ApiResult.Loading)   // Loading (object만 쓰면 패키지 경로 포함 문자열)

Kotlin 1.9 — 실용적 개선#

Enum.entries

.values() 는 호출할 때마다 새 배열을 생성했습니다. .entries는 프로퍼티로 미리 생성된 불변 리스트를 반환합니다.

enum class Direction { NORTH, SOUTH, EAST, WEST }

// 기존 — 배열 복사 발생
val old = Direction.values().toList()

// 1.9+ — 미리 생성된 리스트
val new = Direction.entries
println(new)   // [NORTH, SOUTH, EAST, WEST]

범위 함수 개선

.. 연산자와 until 함수에 Float, Double 범위가 추가되고, rangeUntil 연산자 (..<)가 도입되었습니다.

for (i in 0..<10) {     // 0 이상 10 미만 (1.9+)
    print("$i ")
}
// 기존: for (i in 0 until 10)

Kotlin 1.7 — 빌더와 안정화#

빌더 추론

buildList, buildMap, buildSetStable로 승격되었습니다.

val list = buildList {
    add("A")
    addAll(listOf("B", "C"))
    add(if (condition) "D" else "E")
}   // List<String> 반환

Kotlin 1.5 — value class와 sealed interface#

value class (인라인 클래스)

단일 프로퍼티를 래핑하지만 런타임에 래퍼 객체를 생성하지 않는 클래스. 타입 안전성과 성능을 동시에 확보합니다.

// 런타임에는 Long처럼 동작하지만 타입 안전
@JvmInline
value class UserId(val id: Long)

@JvmInline
value class Email(val address: String) {
    init {
        require(address.contains("@")) { "올바른 이메일 형식이 아닙니다" }
    }
}

fun findUser(id: UserId): User = TODO("DB 조회 구현")

val id = UserId(42L)
// findUser(42L)  // 컴파일 오류 — 타입 안전
findUser(id)      // OK

sealed interface

sealed 수식자를 interface에도 적용할 수 있게 되었습니다. 클래스와 달리 여러 sealed interface를 구현할 수 있습니다.

sealed interface Drawable { fun draw() }
sealed interface Resizable { fun resize(factor: Double) }

// 두 sealed interface 동시 구현 가능
class Image(val path: String) : Drawable, Resizable {
    override fun draw() { println("이미지 그리기: $path") }
    override fun resize(factor: Double) { println("크기 조절: $factor") }
}

Kotlin 1.4 — fun interface (SAM 변환)#

단일 추상 메서드(SAM)를 가진 인터페이스를 fun 키워드로 선언하면 람다로 구현할 수 있습니다.

fun interface Validator<T> {
    fun validate(value: T): Boolean
}

// 람다로 직접 전달
val emailValidator = Validator<String> { it.contains("@") }
println(emailValidator.validate("user@example.com"))   // true

Kotlin Multiplatform — 안정화 여정#

버전상태
1.4 이전실험적 (Experimental)
1.4 ~ 1.8알파/베타
1.9.20Kotlin Multiplatform Stable
2.0+Android/iOS/JVM/Web 타깃 안정

Kotlin 1.9.20부터 Kotlin Multiplatform(KMP)이 Stable 상태가 되었습니다. iOS, Android, JVM, JavaScript, WASM 등 다양한 플랫폼을 단일 Kotlin 코드베이스로 타깃할 수 있습니다.


Context Receivers → Context Parameters#

Kotlin 1.6.20에서 Context Receivers 라는 실험적 기능이 도입되었습니다. 함수가 여러 수신 객체를 컨텍스트로 요구할 수 있도록 하는 기능이었습니다.

// Context Receivers (1.6.20 ~ 2.0, 실험적) — 활성화: -Xcontext-receivers
context(Logger, TransactionScope)
fun processOrder(order: Order) {
    log("주문 처리 시작: ${order.id}")    // Logger의 log()
    beginTransaction()                    // TransactionScope의 beginTransaction()
    // ...
}
Context Receivers는 Context Parameters로 재설계됨

Context Receivers는 안정화 단계에서 한계가 드러나 재설계 되었습니다. Kotlin 2.1부터는 Context Parameters (-Xcontext-parameters) 라는 새로운 설계로 대체됩니다. 매개변수 이름을 명시적으로 부여하고, 호출 시 with(...)로 컨텍스트를 전달하는 방식입니다.

// Context Parameters (2.1+, 실험적) — 활성화: -Xcontext-parameters
context(logger: Logger, tx: TransactionScope)
fun processOrder(order: Order) {
    logger.log("주문 처리 시작: ${order.id}")
    tx.beginTransaction()
}

기존 Context Receivers 기반 코드는 Kotlin 2.x 이후 마이그레이션이 필요합니다. 자세한 내용은 KEEP-367을 참고하세요.


마이그레이션 팁#

1.x → 2.0 마이그레이션

체크 항목조치
K2 컴파일러 활성화build.gradle.kts에서 languageVersion = "2.0"
컴파일러 플러그인 호환성 확인사용 중인 플러그인의 K2 지원 여부 확인
Enum.values().entries성능 개선, 린터 경고 발생
data object 활용sealed 계층의 값 없는 케이스에 적용
// build.gradle.kts — K2 컴파일러 활성화
kotlin {
    compilerOptions {
        languageVersion = KotlinVersion.KOTLIN_2_0
    }
}

기본 JVM 타깃 버전

Kotlin 1.8부터 기본 JVM 타깃이 JVM 8 입니다. Spring Boot 3.x는 JVM 17을 요구하므로, Spring Boot 프로젝트에서는 명시적으로 지정합니다.

// build.gradle.kts
kotlin {
    jvmToolchain(17)   // Java 17 toolchain 사용
}

다음 단계#