Android

Kotlinで初期化を遅延する

投稿日:2018年11月15日 更新日:

はじめに

こんにちは、前回に引き続き、Kotlinの基本的な文法をまとめています。今回はKotlinにおける初期化の遅延についてとなります。
by lazylateinit といったキーワードを初めて目にした時は「呼び出される時に初期化されるのね」という理解(間違いではないのですが言葉足らずでした)しかしておらず、改めて調べることでそれぞれの差異や機能の意図などを掴んでいこうと思います。

初期化の遅延とは

HaskellやScalaでは「遅延評価」と呼ばれているようです。
今回の記事では「インスタンス生成後にプロパティの値を定義できる」という意味で初期化の遅延という表現を使っています。
以下の記事で大まかな概要を理解できましたので、リンクを掲載しておきます。サンプルコードはScalaですが、概ね理解できると思います。
遅延評価とは何か

by lazy

  • 型は何でもOK
  • 一度だけ値の初期化を行う
  • 値はキャッシュされ、二回目以降は最初の値を常に返す
  • readonly

最後の「readonly」が注意点なのですが、これは後述します。
by lazy の記述方法は以下のようになります。 by lazy の後にラムダ式が記述でき、その中で行われた処理の結果を値として、プロパティ msg が初期化されています。

「常に同じ値を返す」という性質なので、findViewByIdで取得したViewを入れたりすると、少し厄介なことになります。
というのも常に同じ値を返すため、例えば textView.text = newValue などとしても変更が反映されません。これはKotlinでは有名なアンチパターンとのこと。
参考: FragmentでKotlinのby lazyを使ってfindViewByIdするとレイアウト反映できない&リークする件
処理が進むにつれて変更されていく値は、次に紹介する lateinit , あるいは Delegates.notNull を使います。

lateinit

  • プリミティブ型は不可
  • val不可、varのみ
  • nullable不可
  • private推奨(初期化が行われる前に外部からアクセスされるのを防ぐため?)

「あとで必ず初期化するけど、インスタンス生成時にはできない」という時に使用します。必ず初期化するのでnon-nullで扱うことが可能となります。
またval不可なので、変更されることが前提となります。ActivityやFragmentのonCreate, onCreateViewで、findViewByIdで取得したViewなどが入ることを想定しているようです。
サンプルコードは下記のようになります。プロパティで変数名だけ宣言する場合、Javaでは値がnullになりますが、lateinitを付けてonCreate内で初期化すればnon-nullとして扱えます。

Delegates.notNull

Delegates.notNull はプリミティブ型に使えます。プロパティにアクセスする前に値をセットする必要があるため、下記のコードはコンパイルエラーとなります。

下記のように sample.nonNullMsg に値を定義してから呼び出しましょう。

ここで「何のためにDelegates.notNullがあるんだろう、lazyかlateinitでいいんじゃないの」という疑問が湧いたのですが

  • lazyは値が不変な場合に使う
  • lateinitはプリミティブ型に使えない

という特徴があったのでした。Delegates.notNullは「可変かつnon-nullな値の初期化を遅延したい」時に使うのが良さそうです。
lazyinitとnotNullの使い分けについてはこちらが参考になりました → Kotlin : ‘notNull delegate’ vs ‘lateinit’

さいごに

いかがでしたでしょうか。「プロパティでnon-nullを保ちつつ、コードの途中で初期化したい。なるべくスマートな書き方で」となると、今回挙げたような記法が一例になると思います。
また、こういった記法を知っていることで、コードの書き手の意図を汲みやすく、また読み手に自分の意図を伝えやすくもなります。
「書きやすく、読みやすい」コードはなかなか難しいですが、常に意識しておきたいです。

おすすめ書籍

Kotlinスタートブック -新しいAndroidプログラミング Kotlinイン・アクション 速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ

blog-page_footer_336




blog-page_footer_336




-Android
-

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

[Android] KotlinでTextToSpeech

1 はじめに2 環境3 MainActivity.kt4 SpeechListener.kt5 activity_main.xml6 さいごに はじめに こんにちは。最近ようやくKotlinに手を付け ...

GCM 2.0からFCMに移行する(AWS SNS対応版)

1 はじめに2 FCM移行で大事なポイント3 Firebaseプロジェクトへの引き継ぎ3.1 Firebaseの初期設定4 依存ライブラリの変更4.1 “com.google.androi ...

【Kotlin】FirebaseAuthenticationでメールアドレスで認証機能を実装

1 はじめに2 レイアウト3 新規登録4 ログイン5 さいごに6 参考7 おすすめ書籍 はじめに こんにちは。miyagawaです。 前回は「FirebaseAuthenticationでGoogle ...

Kotlin OkHttp3で通信を行なった際の備忘

1 はじめに2 ライブラリの導入方法3 Build時にエラーが発生する4 パーミッションの追加5 main関数で同期処理の通信6 onFailureでUnable to resolve host &# ...

【Kotlin + Retrofit】API通信してみる

1 はじめに2 準備3 レイアウトファイルの作成4 APIを実装する5 さいごに6 おすすめ書籍 はじめに こんにちは。miyagawaです。つい最近、ポケモン剣盾を衝動買いしてしました。BW2から全 ...

フォロー

blog-page_side_responsive

2018年11月
 123
45678910
11121314151617
18192021222324
252627282930  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。