안녕하세요 오늘은 lateinit 과 lazy 에 대해서 설명하고 비교해보도록 하겠습니다.
가장 간단하게 설명드리면 늦은 초기화를 하기 위해 사용하는 접근 방식입니다.
늦은 초기화란, 말 그대로 객체의 초기화를 늦게 한다는 것입니다. 물론 '늦은' 이기 때문에 초기화는 반드시 해주셔야 합니다.
늦은 초기화를 사용하는 이유에 대해서 설명을 해보겠습니다.
만약 여러분이 친구를 만난다고 생각해보겟습니다.
class Person {
lateinit var name: String //친구 만날 예정
fun setName() {
name = "John" // 친구 만낫는대 이름이 존
}
fun printName() {
if (::name.isInitialized) {
println("Person's name: $name") // 초기화된 변수 사용
} else {
println("Person's name is not initialized")
}
}
}
fun main() {
val person = Person()
person.setName()
person.printName()
}
코드를 살펴보시면 쉽게 이해하실 수 있으실겁니다.
사용할 변수에 무슨 값이 들어올지 모를때 초기화를 미뤄놀때 lateinit 을 사용합니다.
이때 값은 변할 수 있으므로 반드시 "var"로 선언을 해주셔야 합니다.
또한 Non-null 타입 변수에만 사용할 수 있으며, Nullable 변수에는 사용할 수 없습니다.
변수를 초기화하기 전에 접근하면 UninitializedPropertyAccessException예외가 발생합니다.
변수에 처음 접근하는 시점에서 초기화를 수행하는 지연 초기화 기법입니다.
이해하기 쉽게 코드로 간단한 예를 들어서 설명 드리겟습니다.
fun main() {
lateinit var text : String
val textLength : Int by lazy {
text.length //아직 text에는 무슨 값이 들어올지 모르는 상황
}
text = "BMW" //텍스트 초기화됨 (텍스트 길이가 정해짐)
println(textLength) // 초기화 된 텍스트 길이 출력
코드를 보시면 처음 textLength 에서는 text의 값이 없기 때문에 초기화를 할 수 없습니다.
하지만 후에 text가 초기화되며 textLength 또한 초기화가 가능해졌습니다.
선언 당시에는 초기화 할 방법이 없음 하지만 의존하는 값들이 초기화 된 이후에 초기화 가능
호출 시에 이를 어떻게 초기화 해줄 지에 대해 정의가 가능한 기법이라고 생각하면 됩니다.
코드를 보시면 lateinit 과 다르게 var 가 아닌 val을 사용하고 있습니다.
이는 단 한번의 늦은 초기화가 이루어지고 나면 값이 변하지 않는다는 것을 의미합니다.
| lateinit | lazy | |
|---|---|---|
| 변수가 초기화 되기 전까지는 null이지만, 나중에 반드시 초기화될 것이라는 보장이 있는 경우에 사용됩니다. 즉, null 허용 변수를 피하면서, 초기화를 뒤로 미룰 수 있습니다. | 변수의 초기화를 처음 사용하는 시점까지 늦출 수 있습니다. 이를 통해 리소스를 효율적으로 관리할 수 있습니다. | |
| 사용 가능한 변수 타입 | 원시 타입을 제외한 모든 타입에 사용 가능합니다. (Int, Double 등 원시 타입에는 사용 불가) | 모든 변수 타입에 사용 가능합니다. |
| 초기화 시점 | 코드에서 명시적으로 초기화되어야 합니다. 그렇지 않으면 'lateinit property has not been initialized'라는 예외가 발생합니다. | 처음으로 변수에 접근하는 시점에 자동으로 초기화됩니다. |
| 재 초기화 | 재 초기화가 가능합니다. 즉, 변수에 다시 값 할당이 가능합니다. | 한번 초기화되면 재 초기화가 불가능합니다. |
| 스레드 안전성 | 스레드에 안전하지 않을 수 있습니다. 즉, 여러 스레드에서 동시에 초기화될 수 있습니다. | 스레드에 안전합니다. 기본적으로 동기화되어 있으며, 첫 접근시에만 초기화를 수행합니다. |
| 사용 방법 | 'lateinit var 변수이름: 타입 ' | 'val 변수이름: 타입 by lazy { 초기화 로직 } |