[Kotlin] lazy initialization

sundays·2022년 11월 21일
0

kotlin

목록 보기
8/19

지연 초기화

  • 변수나 객체의 값은 생성시 초기화 필요
  • 클래스에서 프로퍼티 자료형은 null 을 가질 수 없음
  • 하지만 객체의 정보가 나중에 나타나는 경우 나중에 초기화 할 수 있는 방법이 필요한데
    이때 지연 초기화를 위해 lateinitlazy 키워드 사용

lateinit

의존성이 있는 초기화나 unit 테스트를 위한 코드를 작성 시

  • 단위테스트를 위해 임시적으로 객체를 생성 시켜야 하는 경우
  • A클래스 초기화 부분에 B클래스와 의존성을 가지는 경우에 B클래스가 생성되지 않으면 완전하게 초기화 할 수 없는 경우

프로퍼티 지연 초기화

  • var 로 선언된 프로퍼티만 가능
  • 프로퍼티에 대한 게터와 세터를 사용 할 수 없음

예시

class Person {
    lateinit var name: String // 1. 늦은 초기화를 위한 선언

    fun test() {
        if(!::name.isInitialized) { // 2. 프로퍼티의 초기화 여부 판단
            println("not initialized")
        } else {
            println("initialized")
        }
    }
}

fun main() {
    val kildong = Person()
    kildong.test()
    kildong.name = "Kildong" // 3. 이 시점에서 초기화됨(지연 초기화)
    kildong.test()
    println("name = ${kildong.name}")
}

예시2

  • 객체 생성시 lateinit을 통한 지연 초기화 가능
data class Person(var name:String, var age:Int)

lateinit var person1: Person // 1. 객체 생성의 지연 초기화

fun main() {
	person = Person("kildong", 30) // 2. 생성자 호출 시점에서 초기화됨
    print(person1.name + " is " + person1.age.toString())
}

by lazy

  • 읽기 전용의 val로 선언한 객체나 프로퍼티를 나중에 초기화
  • 호출 시점에 by lazy {...} 정의에 의해 블록 부분의 초기화를 진행한다.
  • 불변의 변수 선언인 val에서만 사용 가능하다.(읽기 전용)
  • val이므로 값을 다시 변경할 수 없다.
class LazyTest {
    init {
        println("init block") // 1. 
    }

    val subject by lazy {
        println("lazy initialized") // 3.
        "Kotlin Programming" // lazy 반환값
    }
    fun flow() {
        println("not initialized") //  2.
        println("subject one: $subject") // 4. 최초 초기화 시점!
        println("subject two: $subject") // 5. 이미 초기화된 값 사용
    }
}

fun main() {
    val test = LazyTest()
    test.flow()
}

delegation

  • 하나의 클래스가 다른 클래스에 위임하도록 선언
  • 위임된 클래스가 가지는 멤버를 참조없이 호출
< val|var|class> 프로퍼티 혹은 클래스 이름: 자료형 by 위임자
  • 표준 라이브러리의 무분별한 상속의 복잡한 문제를 방지
  • 단 상속이나 직접 클래스의 기능 확장 불가
  • 위임을 통해서 상속과 비슷하게 최종 클래스의 기능을 사용하며 동시에 추가 확장 가능
  • lazy도 by lazy {...} 처럼 by가 사용되어 위임된 프로퍼티가 사용되었다는 것을 알 수 있습니다.

observable

  • 프로퍼티를 감시하고 있다가 특정 코드의 로직에서 변경이 일어날 때 호출
import kotlin.properties.Delegates

class User {
    // observable 은 값의 번화를 감시하는 일종의 콜백 루틴
    var name:String by Delegates.observable("NONAME") { // 프로퍼티를 위임
        prop, old, new -> // 람다식 매개변수로 프로퍼티, 기존값, 새로운 값
        println("$old -> $new") // 이부분은 이벤트가 발생될때만 실행됨
    }
}
fun main() {
    val user = User()
    user.name = "kildong"// 값이 변경되는 시점에서 첫 이벤트 발생
    user.name = "Dooly" // 값이 변경되는 시점에서 두번째 이벤트 발생
}

vetoable

  • 감시보다는 수여한다는 의미로 반환값에 따라 프로퍼티 변경을 허용하거나 취소
import kotlin.properties.Delegates

fun main() {
    var max: Int by Delegates.vetoable(0) { // 1. 초기값은 0
        property, oldValue, newValue ->
        newValue > oldValue // 2. 조건에 맞지 않으면 거부권 행사
    }

    println(max) // 0
    max = 10
    println(max) // 10

    // 여기서는 기존값이 새값보다 크므로 false임으로 5가 할당되지 않는다
    max = 5
    println(max) // 10
}
profile
develop life

0개의 댓글