[kotlin] lateinit var와 lazy

문돌이 개발자·2023년 3월 18일

lateinitlazy는 모두 초기화를 지연시켜준다.

lateinit는 var로 선언되어야 하고 변수에 객체를 재할당할 수 있다. 반면 lazy로 초기화되는 변수는 val로 선언되어야 하고 재할당할 수 없다.

lateinit은 getter와 setter를 커스텀할 수 없지만 lazy는 할 수 있다.

lateinit은 primitive 타입을 할당할 수 없지만 lazy는 primitive 타입을 할당할 수 있다.

lateinit은 thread safety 설정을 제공하지 않지만 lazy는 제공한다. synchronized, publication, none 중 선택할 수 있다.

val a : String by lazy(LazyThreadSafetyMode.SYNCHRONIZED){"a"}
val b : String by lazy(LazyThreadSafetyMode.PUBLICATION){"b"}
val c : String by lazy(LazyThreadSafetyMode.NONE){"c"}
  • SYNCHRONIZED는 오직 하나의 스레드만이 lazy인스턴스를 초기화하는 것을 허용한다.
  • PUBLICATION은 여러 스레드가 초기화 함수에 접근하여 값을 반환할 수 있지만 처음에 반환된 값만 lazy 인스턴스로 사용된다.
  • NONE은 lazy인스턴스에 여러 스레드가 접근할 시의 동작이 정의되지 않았으며 이 설정은 싱글스레드 외의 환경에서는 절대 초기화되지 않는걸 보장할 수 없는 이상 사용하지 않는 것을 권장한다.

lateinit에선 ::변수명.isinitialized를 통해 변수의 초기화여부를 확인할 수 있다.

lateinit var b: String
//Returns true if this lateinit property has been assigned a value, and false otherwise.
::b.*isInitialized*

반면 lazy에선 Delegate를 분리하여 isinitialized() 메소드를 통해 초기화 여부를 확인할 수 있다.

val aDelegate =lazy{"a"}
val a by aDelegate
aDelegate.isInitialized()

lateinit는 변수의 초기화 여부를 컴파일러가 체크하지 않아 초기화하지 않고 변수를 사용할 시에 런타임 에러가 날 수 있다. 반면에 lazy 는 초기화 여부를 컴파일러가 체크하여 컴파일 타임에 에러를 발생시킨다.

lateinit는 초기화 이후에도 값이 지속적으로 변할 가능성이 있을 때 사용하며, lazy는 초기화 이후에는 람다로 반환받은 값을 캐싱하여 이를 지속적으로 반환하기 때문에 값이 변하지 않고 초기화가 무거운 작업일 경우에 사용한다.

lateinit은 null로 초기화할 수 없지만 lazy는 null로 초기화 할 수 있다. lazy는 초기화되기 전에 접근할 수 없기 때문에 굳이 null로 초기화를 해서 사용할 일이 있지 않은 이상 null로 초기화할 일이 없다.

❓ 궁금한 점은 var로도 선언만 해두면 초기화는 나중에 할 수 있는데 왜 `lateinit`이 필요할까?
📖 var a : String과 lateinit var a : String의 차이점은 var로 선언한 변수는 초기에 값을 지정할 수 있고 null로 초기화할 수 있지만 `lateinit`으로 선언한 변수는 초기값을 지정해 줄 수 없고 null로 초기화할 수 없다. 따라서 null이 되어선 안되는 변수의 초기화를 지연시키고 싶을 때 `lateinit`를 사용하면 된다.

참고:
lateinit vs lazy Property in Kotlin

profile
까먹고 다시 보려고 남기는 기록

0개의 댓글