Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

Kotlin lateinit vs lazy – 속성 초기화 방식 완벽 비교 가이드

Kotlin은 프로퍼티(property)의 지연 초기화를 위해 lateinitlazy라는 두 가지 서로 다른 메커니즘을 제공합니다. 두 기능 모두 값의 초기화 시점을 실제로 필요한 순간까지 미루는 역할을 하지만, 동작 방식과 적용 조건이 다르기 때문에 상황에 맞게 선택하는 것이 중요합니다.

이 글에서는 lateinit과 lazy의 차이점을 살펴보고, 실제 애플리케이션에서 각각을 어떻게 활용할 수 있는지 예제와 함께 알아보겠습니다.

lateinit이란?

변수를 lateinit으로 선언하려면 해당 변수 선언부에 lateinit 키워드를 붙이기만 하면 됩니다. 다만 Kotlin에서 lateinit을 사용하려면 다음 조건들을 반드시 지켜야 합니다.

  • 가변 변수(mutable variable)에만 사용할 수 있습니다. 즉, var 키워드와 함께 사용해야 합니다.

  • 널이 아닌(non-nullable) 타입에만 허용됩니다.

  • Int, Boolean 등 원시 타입(primitive type)에는 사용할 수 없습니다.

  • 커스텀 gettersetter가 정의되어 있지 않은 프로퍼티에만 적용할 수 있습니다.

lateinit은 의존성 주입(DI) 프레임워크나 Android의 뷰 바인딩처럼, 객체 생성 이후 외부에서 값이 할당되는 경우에 특히 유용합니다.

lateinit 예제

아래 예제에서는 변수를 lateinit으로 선언하고, 프로그램 전체에서 이를 어떻게 접근하는지 확인해 보겠습니다. ::name.isInitialized를 사용하면 값이 할당되었는지 여부를 안전하게 검사할 수 있습니다.

class Tutorial {

    lateinit var name: String

    fun checkLateInit() {
        // 값이 할당되어 있는지 검사
        if (this::name.isInitialized) {
            println("이미 초기화된 값: $name")
        } else {
            // name 초기화
            name = "www.tutorialspoint.com/"
            println(name)
        }
    }
}

fun main() {
    val obj = Tutorial()
    obj.checkLateInit()
}

실행 결과

위 코드를 실행하면 다음과 같은 출력이 생성됩니다.

www.tutorialspoint.com/

lazy 초기화란?

Kotlin은 효율적인 메모리 관리를 위해 lazy 초기화(lazy initialization) 기능을 제공합니다. lazy 키워드를 사용하면 해당 객체는 실제로 호출되는 시점에 생성되며, 그 전까지는 객체가 만들어지지 않습니다.

lazy()는 람다(lambda)를 인자로 받아 Lazy 인스턴스를 반환하는 함수입니다. 반환된 인스턴스는 위임(delegate)으로 동작하여, 적용된 프로퍼티가 처음 접근될 때 람다를 실행하고 그 결과를 캐싱합니다. 즉, 불필요한 객체 초기화를 방지하기 위해 설계된 기능입니다.

  • 널이 아닌(non-nullable) 변수에 사용하는 것이 일반적입니다.

  • 변수는 반드시 val로 선언해야 하며, var는 허용되지 않습니다.

  • 객체는 단 한 번만 초기화되며, 이후에는 캐시된 값을 그대로 반환받습니다.

  • 애플리케이션에서 실제로 사용되기 전까지는 객체가 초기화되지 않습니다.

lazy 예제

다음 예제에서는 lazy 변수 "myName"을 선언합니다. 초기화 블록은 처음 호출될 때 단 한 번만 실행되며, 값이 초기화된 후에는 애플리케이션 전체에서 동일한 값을 기억합니다. lazy 초기화로 한 번 할당된 값은 다시 재할당할 수 없습니다.

class Demo {
    val myName: String by lazy {
        println("Welcome to Lazy declaration")
        "www.tutorialspoint.com"
    }
}

fun main() {
    val obj = Demo()
    println(obj.myName)
    println("같은 객체에 대한 두 번째 호출--" + obj.myName)
}

실행 결과

위 코드를 실행하면 다음과 같은 출력이 생성됩니다.

Welcome to Lazy declaration
www.tutorialspoint.com
같은 객체에 대한 두 번째 호출--www.tutorialspoint.com

출력 결과에서 볼 수 있듯이 "Welcome to Lazy declaration" 문구는 첫 번째 호출 시에만 출력됩니다. 두 번째 호출부터는 초기화 로직을 다시 실행하지 않고 캐시된 값이 바로 반환되기 때문입니다.

lateinit vs lazy 비교 정리

구분lateinitlazy
선언 키워드var만 가능val만 가능
원시 타입사용 불가사용 가능
초기화 시점외부에서 직접 할당첫 접근 시 자동 초기화
재할당여러 번 가능불가(단 한 번만 초기화)
주요 용도DI 프레임워크, Android 뷰 바인딩 등생성 비용이 큰 객체의 지연 생성

마무리

정리하면, 값을 나중에 직접 할당해야 하는 경우에는 lateinit이 적합하고, 최초 접근 시 자동으로 한 번만 초기화되기를 원하는 경우에는 lazy가 적합합니다. 두 기능의 특성과 제약 조건을 정확히 이해하고 있으면, 더 안전하고 효율적인 Kotlin 코드를 작성할 수 있습니다.