Kotlin 初期化の遅延(lateinit, by lazy)

lateinit

クラスのプロパティは通常初期化が必要だが、lateinitを使うと初期化を遅らせることができる。 Intなどのプリミティブ型には使用できず、Null許容型にも使用できない。また、varプロパティにしか使用できないという制限がある。

class Foo {
    lateinit var name: String        // init()を呼び出す前に初期化が必要
    fun init(name: String) { this.name = name }
}

by lazy

lateinitに似た仕組みとしてby lazyがある。IntやNull許容型にも指定できるが、valプロパティにしか使用できない。 宣言部には初期化用のラムダ式を記述する。 その値が最初に必要になったとき、つまり初めて参照された時点で初期化される。

次の例のように、DB接続オブジェクトを一度だけ初期化したい場合に活用できる。

fun connectToDB() {
    ...
    return db
}
fun main() {
    val db by lazy { connectToDB() }
}

実際に初期化が一度だけ行われるか、簡単な例を書いて実行してみよう。

class ByLazy {
    val greeting: String by lazy {
        println("Greeting is Initialized!!!!") // 一度だけ実行される
        "Hello"
    }
}

fun main() {
    val byLazy = ByLazy()
    println("Greeting is Not Initialized")
    println("Greeting one : ${byLazy.greeting}")
    println("Greeting two : ${byLazy.greeting}")
    println("Greeting three : ${byLazy.greeting}")
}

Output:

Greeting is Not Initialized
Greeting is Initialized!!!!
Greeting one : Hello
Greeting two : Hello
Greeting three : Hello

結果を見ると、変数greetingを最初に取得したときだけ"Greeting is Initialized!!!!"が表示され、それ以降は表示されないことが分かる。