코틀린 lazy, lateinit 이해하기 | 초기화 | by lazy, delegation

늦은 초기화

변수를 선언하고 바로 사용하는 경우도 있지만, 선언을 해놓고 추후에 변경해야 되는 경우가 있다.

예를 들면,

class T {
    var name:String? = null

    
    fun test() {
        name = "abcd"

        if (name.length == 0) { // compile Error

        }
        
        if (name?.length) { }
        if (name!!.length) { }
    }
}

클래스 코드를 작성할 때는 모르고 실행하는 과정에서 값을 세팅할 때 null 을 사용하는 코드를 많이 보았을 것이다. 자바 방식으로 짜다보면 NPE 에러를 많이 경험했을 것이다.

null 을 사용해서 쓰면 ? 를 사용해서 null 안정성을 매번 체크하거나 !! 키워드를 사용해야 강제로 null이 아니다라는 방식의 코딩을 해야 한다. 이는 그닥 효율적이 않은 코딩 방식이다.


</br>

1. lateinit 초기화

위의 코드를 lateinit 코드를 사용해서 바꿔보자

class T {
    lateinit var name: String

    lateinit var age: Int // Compile Error -> var age by Delegates.notNull<Int>()

    fun test() {
        name = "abcd"

        if (name.length == 0) {

        }

    }
}

lateinit 을 사용하면 ? 또는 !! 없이 변수를 사용할 때 할당하고 쉽게 이용할 수 있다.

주의할 점은 사용하기 전에 할당을 해야 ‘lateinit property name has not been initialized’ 에러를 피할 수 있다. Primitive Type은 lateinit 을 사용할 수 없고 Delegate 형태로 위임해서 사용해야 한다.


</br>

2. lazy 초기화

lateinit 은 var 로 선언하기에 안정성은 떨어진다. lazy 를 통한 초기화는 val 키워드를 통해 읽기전용 변수로 사용할 수 있다.

fun main() {
    val t = T()
    println(t.test())
}

class T {
    private val name: String by lazy {
        println("by lazy")
        "ABCD"
    }
    
    fun test() {
        println(name)
    }
}

name 의 변수를 참조할 때 변수가 할당이 되는 특징을 가진다.

추가적으로 lazy(옵션) synchronized, publication, none 키워드를 사용할 수 있다. synchronized 는 한 스레드만 값을 계산할 수 있으며 모든 쓰레드가 같은 값을 가진다. publication 은 초기화 과정을 여러 스레드가 동시에 수행할 수 있으나 만약 다른 스레드에서 초기화하여 할당된 값이 있다면 그 값을 반환 NONE 은 별도의 동기화 처리가 없음



Related Posts