[코틀린기초] 27. 지연 초기화
클래스에서는 기본적으로 선언하는 프로퍼티 자료형들은 null을 가질 수 없다.
하지만 객체의 정보가 나중에 나타나는 경우 나중에 초기화 할 수 있는 방법이 필요하다.
그런 경우에 lateinit 과 lazy 키워드를 사용하여 지연 초기화를 한다.
lateinit을 사용한 지연 초기화
-
의존성이 있는 초기화나 unit 테스트를 위한 코드를 작성 시 사용 ex. car 클래스가 engine 객체가 생성되지 않으면 완전하게 초기화 할 수 없는 경우 ex. 단위테스트를 위해 임시적으로 객체를 생성 시켜야 하는 경우
-
프로퍼티 지연 초기화 클래스를 선언할 때 프로퍼티 선언은 null을 허용하지 않으므로, lateinit 키워드를 사용하면 프로퍼티에 값이 바로 할당되지 않아도 된다.
### lateinit의 제한
- var로 선언된 프로퍼티만 가능
- getter와 setter 사용불가
- 객체 생성 또한 지연 초기화가 가능
- 반드시 초기화가 된 이후에 프로퍼티에 접근하자. 안그러면 exception
class Person{
lateinit var name: String // 늦은 초기화를 위한 선언
fun test(){
if(!::name.isInitialized){ // 프로퍼티 초기화 여부 판단
println("not isInitialized")
}
else{
println("initialized")
}
}
}
lateinit var person1 Person // 객체 생성의 지연 초기화
fun main(){
val kildong = Person()
kildong.test()
kildong.name = "Kildong" // 이 시점에서 초기화됨
kildong.test()
}
## lazy를 이용한 지연 초기화
- 호출 시점에 by lazy {…} 정의에 의해 블록 부분의 초기화를 진행한다.
- val에서만 사용 가능하다 (읽기 전용)
class LazyTest{
init{
println("init block")
}
private val subject by lazy { // 늦은 초기화. subject가 접근되는 시점에 초기화된다.
println("lazy initialized")
"Kotlin Programming" // lazy 반환 값
}
fun flow(){
println("not initialized")
println("subject one: $subject") // 이때 subject가 초기화 된다!!
println("subject who: $subject") // 이미 초기화 된 값을 사용한다.
}
}
fun main(){
val test = LazyTest()
test.flow()
}
### by lazy로 선언된 객체 지연 초기화
class Person(val name: String, val age: Int)
fun main(){
var isPersonInstantiated: Boolean = false // 초기화 확인 용도
val person: Person by lazy{ // lazy를 사용한 person 객체의 지연 초기화
isPersonInstantiated = true
Person("Kim",23) // 이 부분이 lazy객체로 반환됨.
}
val personDelegate = lazy { Person("Hong",40) } // 위임 변수를 사용한 초기화
println("person.name = ${person.name}") //이 시점에서 초기화
println("personDelegate.value.name = ${personDelegate.value.name}") // 이 시점에서 초기화
}
### by lazy의 모드
- SYNCHTONIZED : 락을 사용해 단일 스레드만이 사용하는 것을 보장 (기본 값)
- PUBLICATION : 여러 군데서 호출될 수 있으나 처음 초기화 된 후 반환 값을 사용
- NONE : 락을 사용하지 않기 때문에 빠르지만 다중 스레드가 접근 가능 (값의 일관성 보장 x)
private val model by lazy(mode= LazyThreadSafetyMode.NONE){
Injector.app().transactionModel() // 이 코드는 단일 스레드의 사용이 보장될 때
}