Kotlin 1.9.0

강보훈·2023년 10월 9일
0

변경점

  1. k2 컴파일러 베타버전
  2. Replacement of the enum class values function
  3. Data object symmetry with data classes
  4. Support for secondary constructors with bodies in inline value classes

Replacement of the enum class values function

기존에는 enum의 values() 를 통해 enum 값들을 가져왔다면 1.8.20에서 Experimental feature였던 기능인 entries가 안정화 단계로 오면서 이제는 더 모던한 방법으로 enum값을 가져올 수 있다.

enum class TestEnum(val data: String){
    A("123"),
    B("456"),
    C("789"),
    D("1");
}

TestEnum.entries.find {it.data == "123"} // nullable, findOrNull 없음

Data object symmetry with data classes

Sealed class 와 같은 구조에서 사용가능한 상태를 관리할 때 편리하다
object로만 선언하는 경우 toString을 따로 구현해야하지만 data object로 선언하는 경우 그럴필요가 없다.
아래와 같은 상태 관리를 위한 sealed interface가 있을 때

sealed interface TestStatus {
    object Loading: TestStatus
    data class Success(val response: String): TestStatus
    object Fail: TestStatus
}

각 상태를 호출해보면

TestStatus$Loading@5b464ce8
Success(response=Success Response)
TestStatus$Fail@17c68925

이와 같이 나오면서 상태값을 보고 판단하기에 조금 번거롭다.
object -> data object로 전환하면

sealed interface TestStatus {
    data object Loading: TestStatus
    data class Success(val response: String): TestStatus
    data object Fail: TestStatus
}
Loading
Success(response=Success Response)
Fail

이와 같이 알아보기 편하게 나온다.

그리고 equals()의 경우 data object는 싱글턴구조이지만 reflection등을 통해 추가로 만들어내는 경우도 있기에 === 를 통한 레퍼런스 비교가아닌 == 를 사용하는 것은 권장한다.

마지막으로 hashCode()를 통해 만들어내는 해쉬값도 모두 동일하기에 참고!

Support for secondary constructors with bodies in inline value classes

value class에 대해서 먼저 정리하고 오자

value class란?

함수의 인자로 혹은 클래스의 프로퍼티로 특정 값만 올 수 있도록 하려면 제일 간단한 방법은 wrapper class를 만들어서 사용하는 방법이다. 하지만 매번 불필요한 오버헤드가 발생하며 Primitive type이 아니라 최적화도 이루어지지 않는다. 이런 문제점을 하기 위해서 value class는 런타임 시 객체를 제거하고 해당 자리의 프로퍼티로 생성된다.

주의점
  1. value class는 단 하나의 값만 가질 수 있다.
  2. val만 사용이 가능하다
  3. 최상위 혹은 nested class에서만 사용해야한다. local, inline class는 안됨

예를 들어 회원 정보를 생성할 때

data class UserInfo(
    val id: String,
    val email: EmailInfo,
    val pw: String
)

@JvmInline
value class EmailInfo(val email: String){
    init {
        require(email.contains("@"))
    }

    fun getID() = email.split("@").firstOrNull()

    fun getHost() = email.split("@").lastOrNull()

}

와 같이 이메일의 형식제한과 이메일의 앞 뒤를 가져오는 간단한 함수도 사용이 가능하다.
다른 예제로는 asyncAfter 함수의 실행 딜레이를 결정할 때 IOS에서는 .seconds(), .minute() 와 같은 함수를 제공하는데 value class를 통해서도 동일하게 만들어서 가독성과 성능 모두 챙길 수 있다.

맹글링이란?

To be continue..

1.9.0에서의 value class 변경점

기존에는 value class에서는 public primary constructors만 생성이 가능했지만 이제는 private으로 생성 및 추가 생성자를 만들어서 사용이 가능하다.

@JvmInline
value class EmailInfo(private val email: String){
    init {
        require(email.contains("@"))
    }

    constructor(id: String, host: String): this("$id@$host") {
        require(id.isNotBlank() && host.isNotBlank())
    }

    fun getID() = email.split("@").firstOrNull()

    fun getHost() = email.split("@").lastOrNull()

}
profile
3년차 안드로이드 개발자입니다.

0개의 댓글