以下の内容はhttps://uga-box.hatenablog.com/entry/2024/09/02/000000より取得しました。


【Kotlin】lateinit の使い所

Kotlin では原則 Null 非許容であるため、通常 varval のプロパティは、宣言時にすぐに初期化されなければならない

ただ、lateinit という修飾子を使えばプロパティの初期化を後回しにすることができることを知った

ところで、この折角の Null 非許容を破ってしまうlateinitはいつ使うべきなのか、使い所がわからなかったので調べた

lateinit の基本的な特徴

  • var にのみ使用できる: lateinitvar 変数にのみ使用可能で、val 変数には使えない。つまり、lateinit プロパティは再代入が可能
  • プリミティブ型には使用不可: IntBooleanDouble などのプリミティブ型には使えない。lateinit はオブジェクト型に対してのみ使用可能
  • null 許容型ではない: lateinit プロパティは null 許容型ではなく、必ず後で非 null の値が代入されることを期待している。もし初期化前にアクセスすると、UninitializedPropertyAccessException がスローされる

lateinit を使うべき場面

lateinit は、プロパティを後から初期化する必要がある場合に使われる

これにより、コンストラクタ内で必ず初期化できない状況や、初期化を遅らせたい場合に便利

1. 依存性注入(Dependency Injection)

依存性注入フレームワークを使う場合、プロパティを後で初期化する必要がある

通常、DI フレームワークはオブジェクト生成後にプロパティの依存関係を注入するため、Kotlin の通常の初期化ルールに従わないことがある

class MyService {
    lateinit var database: Database

    fun initialize() {
        database.connect()
    }
}

この例では、database プロパティはオブジェクト生成時にはまだ初期化されておらず、後で依存性注入で設定される

2. Android 開発

lateinit は、Android 開発において UI 要素を後で初期化するためによく使われるらしい

Android開発はしたことないが、ActivityFragmentonCreate メソッドの中で ビューの初期化が行われることが一般らしく、その時点でプロパティを初期化したい場合に lateinit が便利とのこと

class MainActivity : AppCompatActivity() {
    lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        textView = findViewById(R.id.text_view)  // 後で初期化
        textView.text = "Hello, World!"
    }
}

textViewonCreate 内で初期化されるため、宣言時に lateinit を使っている

これにより、null 許容型を使わずに、初期化の遅延を実現している

3. ユニットテスト

テスト時にプロパティをモックオブジェクトやテストデータで初期化する場合

プロパティをテストのセットアップ中に初期化するために、lateinit を使う

class MyTest {
    lateinit var mockService: MyService

    @Before
    fun setUp() {
        mockService = mock(MyService::class.java)
    }

    @Test
    fun testService() {
        mockService.doSomething()
        // テストコード...
    }
}

上の例ではテスト前のセットアップで mockService を初期化しており、テストの実行時に lateinit を使って初期化が遅延されている

初期化確認の方法

lateinit プロパティが初期化されたかどうかを確認する方法として、::プロパティ名.isInitialized を使うことができる

これにより、プロパティが初期化されているかを確認し、未初期化の場合に例外を防ぐことが可能

class MyClass {
    lateinit var name: String

    fun printName() {
        if (::name.isInitialized) {
            println(name)
        } else {
            println("name is not initialized")
        }
    }
}



以上の内容はhttps://uga-box.hatenablog.com/entry/2024/09/02/000000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14