lateinit / lazy
보통은 클래스에서 기본적으로 선언하는 프로퍼티는 null 값을 가질 수 없다.
그러므로 반드시 초기화가 되어야 하는것이 규칙인데, 초기화를 미룰 때 지연초기화 (lateinit, lazy)를 사용한다.
언제 사용할까?
의존성이 있는 초기화나 유닛 테스트를 위한 코드를 작성하면서, 설정에 의한 초기화를 할 때 불편하다.
Car클래스의 초기화 부분이 Engine클래스와 의존성을 가질 때, Engine 객체가 생성되지 않으면
완전하게 초기화 할 수 없다. 이처럼 특정 객체에 의존성이 있을 때 지연초기화를 해야한다.
lateinit 지연초기화 예시
class Person2 {
lateinit var name: String //지연초기화 선언
fun test() {
if(!::name.isInitialized) {
println("not initialized")
} else {
println("initialized")
}
}
}
fun main() {
val kildong = Person2() // 객체를 생성해도 name은 초기화되지 않는다. 지연초기화를 허용했기에
kildong.test()
kildong.name = "kildong" // 이 시점에서 초기화됨 (지연초기화)
kildong.test()
println("name =${kildong.name}")
}
출력값은
not initialized
initialized
name = kildong
이 나오는데, 지연초기화가 언제 되는지 코드블록을 보고 생각해보자
lateinit은 var 에만 사용이 가능하다. val엔 사용이 불가능하다.
lazy 지연초기화 사용예시
class Person3(val name: String, val age: Int)
fun main() {
var isPersonInstantiated: Boolean = false
val person : Person3 by lazy {
isPersonInstantiated = true
Person3("kim", 23)
}
val personDelegate = lazy { Person3("hong", 40)}
println("person Init: $isPersonInstantiated")
println("personDelegate Init: ${personDelegate.isInitialized()}")
println("person.name = ${person.name}") // 이 시점에서 초기화
println("personDelegate.value.name = ${personDelegate.value.name}") // 이 시점에서 초기화
println("person Init: $isPersonInstantiated")
println("personDelegate Init: ${personDelegate.isInitialized()}")
}
출력값은
person Init: false
personDelegate Init: false
person.name = kim
personDelegate.value.name = hong
person Init: true
personDelegate Init: true
언제 지연초기화가 되었는지 확인해보자.
lazy는 val에만 사용가능하다.