Kotlin Academy · レッスン

lateinitと遅延初期化

後から代入するプロパティにはlateinitを、遅延計算にはby lazyを使用します。

レッスン 4/413 ステップ

「lateinitと遅延初期化」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。

遅延初期化のための2つの方法

コンストラクターの実行時にプロパティを初期化できない場合があります。Kotlin には、後から代入するvar向けのlateinitと、最初のアクセス時に計算するval向けのby lazyが用意されています。

lateinit の基本

lateinit varを使うと初期化を遅らせることができます。変数は null 非許容かつプリミティブ型ではないvarでなければなりません。代入前にアクセスするとUninitializedPropertyAccessExceptionがスローされます。

class Service {
    lateinit var name: String
    fun init(value: String) { name = value }
}
fun main() {
    val s = Service()
    s.init("MyService")
    println(s.name)
}

lateinit を使う理由

初期化がコンストラクターの外部で行われる依存性注入、テストフィクスチャ、またはフレームワークが管理するライフサイクル(Android のビューや Spring の Bean など)にはlateinitを使用します。

class Repository {
    lateinit var db: String   // assigned later by DI framework
    fun query() = "querying $db"
}
fun main() {
    val r = Repository()
    r.db = "postgres://localhost"
    println(r.query())
}

isInitialized による確認

::propName.isInitializedを使うと、lateinitプロパティに値が代入済みかどうかを確認できます。

class Foo {
    lateinit var bar: String
    fun status() = if (::bar.isInitialized) "set to $bar" else "unset"
}
fun main() {
    val f = Foo()
    println(f.status()) // unset
    f.bar = "hi"
    println(f.status())
}

lateinit の制限

プリミティブ型(Int、Boolean など)、null 許容型、またはvalにはlateinitを使用できません。これらの規則はコンパイラーによって強制されます。

// VALID:
lateinit var name: String
// INVALID:
// lateinit var count: Int       // primitives not allowed
// lateinit val constant: String // val not allowed
// lateinit var maybe: String?   // nullable not allowed
fun main() { name = "ok"; println(name) }

by lazy の基本

by lazyを使うと、valの初期化を最初のアクセスまで遅らせることができます。ラムダは1回だけ実行され、結果がキャッシュされます。

val expensive: String by lazy {
    println("Computing...")
    "result"
}
fun main() {
    println(expensive) // Computing... then result
    println(expensive) // result (cached)
}

by lazy を使う理由

初期化にコストがかかり、必要にならない可能性がある場合(後で使うためにキャッシュする場合)や、初期化がすでに構築済みの他のプロパティに依存する場合はby lazyを使用します。

class Config {
    val parsed: Map<String, String> by lazy {
        println("parsing config...")
        mapOf("host" to "localhost", "port" to "8080")
    }
}
fun main() {
    val c = Config()
    println("config object created — not parsed yet")
    println(c.parsed["host"]) // now parses
    println(c.parsed["port"]) // cached
}

lazy のスレッドセーフ性モード

デフォルトでは、by lazyはLazyThreadSafetyMode.SYNCHRONIZEDを使用します。並行実行しても問題ない初期化にはPUBLICATIONを、シングルスレッドでの性能を優先する場合はNONEを使用します。

val safe: String by lazy { "thread-safe" }
val fast: String by lazy(LazyThreadSafetyMode.NONE) { "fast, single-thread" }
fun main() {
    println(safe)
    println(fast)
}

lateinit と lazy の比較

lateinit:varで、外部から代入します。by lazy:valで、最初のアクセス時にプロパティ自身が計算します。

class Demo {
    lateinit var injected: String         // assigned by caller
    val computed: String by lazy { "computed once" }
}
fun main() {
    val d = Demo()
    d.injected = "from outside"
    println(d.injected)
    println(d.computed)
}

他のプロパティを読み取る lazy

lazy プロパティは、先に初期化された他のプロパティを読み取り、それらを組み合わせることができます。

class User(val first: String, val last: String) {
    val fullName: String by lazy { "$first $last" }
}
fun main() {
    val u = User("Ada", "Lovelace")
    println(u.fullName)
}

実践的なパターン

同じクラス内で、DI にはlateinitを、派生状態にはby lazyを組み合わせます。

class App {
    lateinit var config: Map<String, String>
    val host: String by lazy { config["host"] ?: "localhost" }
}
fun main() {
    val app = App()
    app.config = mapOf("host" to "api.example.com")
    println(app.host) // api.example.com
}

クイックチェック

valプロパティの初期化を最初のアクセスまで遅らせるキーワードはどれですか?

まとめ

フレームワークや DI によって後から代入される null 非許容の可変プロパティには、lateinit varを使用します。最初のアクセス時に1回だけ計算する読み取り専用の値には、val by lazyを使用します。状態は::prop.isInitializedで確認できます。

無料で開始

AI チューターと学ぶ Kotlin — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
51
レッスン
203

よくある質問

「lateinitと遅延初期化」レッスンは無料ですか?

はい。「lateinitと遅延初期化」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。

「lateinitと遅延初期化」で何を学びますか?

後から代入するプロパティにはlateinitを、遅延計算にはby lazyを使用します。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Kotlin Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「lateinitと遅延初期化」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このKotlin Academyレッスンでコードを書いて実行できますか?

はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. プライマリコンストラクターとプロパティパラメータ
  2. initブロックと初期化の順序
  3. fieldを使ったカスタムGetterとSetter
  4. lateinitと遅延初期化
← Kotlin Academyに戻る