아티클 목록으로 가기

Lazy의 내부 동작 원리

skydovesJaewoong Eum (skydoves)||6분 소요

Lazy의 내부 동작 원리

코틀린은 매우 유용한 위임(delegate)인 lazy를 제공합니다. lazy 함수는 프로퍼티의 값이 처음 접근되는 시점에 한 번만 계산된 뒤, 이후 모든 호출에서는 캐싱된 결과를 반환하는 프로퍼티를 생성합니다. 공개 API 자체는 무척 단순하지만, 내부를 깊이 들여다보면 Lazy 인터페이스를 기반으로 정교하게 설계된 시스템이 존재하며, 서로 다른 스레드 안전성 요구 사항에 맞춰 특화된 여러 구현체가 준비되어 있습니다. 평소 by lazy { ... }를 습관적으로 사용하시는 분이라면, 내부에서 어떤 일이 벌어지는지 이해하면 보다 적절한 모드를 선택하는 데 큰 도움이 될 것입니다.

lazy 메커니즘 전체는 간결하면서도 독창적인 하나의 인터페이스를 중심으로 구축되어 있습니다. 이 인터페이스는 지연 초기화(lazy initialization) 값을 나타내는 모든 객체가 준수해야 할 공개 계약(contract)을 정의합니다.

public interface Lazy<out T> {
    /**
     * 현재 `Lazy` 인스턴스의 지연 초기화된 값을 반환합니다.
     * 한 번 초기화된 이후에는 이 `Lazy` 인스턴스의 남은 생명주기 동안 값이 변경되어서는 안 됩니다.
     */
    public val value: T

    /**
     * 이 `Lazy` 인스턴스의 값이 이미 초기화되었으면 `true`를, 그렇지 않으면 `false`를 반환합니다.
     * 이 함수가 한 번 `true`를 반환하면, 해당 `Lazy` 인스턴스의 남은 생명주기 동안 계속 `true`를 반환합니다.
     */
    public fun isInitialized(): Boolean
}
  • value: T: 읽기 전용 프로퍼티이며, Lazy의 핵심 진입점(entry point)입니다. 처음 접근하는 순간 초기화 람다가 실행되고, 이후의 모든 접근에서는 캐싱된 결과를 곧바로 돌려줍니다.
  • isInitialized\(\): Boolean: 초기화 과정을 실제로 트리거하지 않으면서, 초기화 람다가 이미 실행되었는지 확인할 수 있는 함수입니다. 지연 프로퍼티의 상태를 안전하게 파악하고 싶을 때 유용하게 활용할 수 있습니다.

이 인터페이스가 바로 프로퍼티 위임(property delegation)의 토대가 됩니다. getValue 연산자 확장 함수인 operator fun <T> Lazy<T>.getValue(...)는 아래 코드에서 볼 수 있듯이, 프로퍼티 읽기를 단순히 lazy.value 프로퍼티에 위임하는 구조입니다.

/**
 * [T] 타입의 읽기 전용 프로퍼티를 [Lazy] 인스턴스에 위임하기 위한 확장 함수입니다.
 *
 * 이 확장 함수를 통해 Lazy 인스턴스를 프로퍼티 위임에 사용할 수 있습니다.
 * `val property: String by lazy { initializer }`
 */
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value

이 아티클은 구독자 전용입니다

Dove Letter를 구독하시면 안드로이드, 코틀린 개발 관련 독점 아티클의 전체 내용을 볼 수 있습니다.

구독하기
아티클 목록으로 가기