SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

【最新Kotlinアップデート解説】バージョン1.1からの変更点総まとめ

Kotlin最新アップデートまとめ ──連載概要とwhen・lateinit・アンダースコアの新しい使い方など

【最新Kotlinアップデート解説】バージョン1.1からの変更点総まとめ 第1回

  • X ポスト
  • このエントリーをはてなブックマークに追加

 Android開発において第1言語の地位を獲得したKotlin。JVM言語であるがゆえに、もちろん、Android以外でも利用されています。そのKotlinの最初の安定版であるバージョン1がリリースされたのが2016年2月です。その後、アップデートを重ね、バージョン2が2024年5月にリリースされました。この連載では、8年間に及ぶアップデート、すなわち、バージョン1.1以降、2.0までに施されたアップデートに関して、バージョン横断でテーマ別に紹介していきます。その初回である今回は、連載の内容を概観するとともに、細かいテーマを複数紹介します。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 本連載は、Kotlinの変更点を紹介する連載です。

 Kotlinは、JVM言語のひとつとして開発され、最初の安定版であるバージョン1がリリースされたのが2016年2月です。その後、Android開発における第1言語の座を占めるようになったのを機に、多くの人に利用されるようになってきています。もちろん、Android開発以外でも利用されており、筆頭JVM言語としての地位を獲得しています。

 そのようなKotlin言語のバージョン2.0が、2024年5月にリリースされました。バージョン1から2までの8年間、順当にアップデートを重ねてきており、さまざまな新機能が追加されています。本連載では、この8年間にバージョン1.1以降で追加されたさまざまな変更点を整理し、バージョン横断で各テーマごとに紹介していきます。具体的には、以下のテーマを予定しています。

  • 関数に関する新機能
  • クラスとインターフェースに関する新機能
  • コルーチン

 第1回目である今回は、上記テーマに含まれていないものの、重要な変更点を取り上げます。これらは、ひとつのテーマでは連載1回分の内容には少ないものばかりを、詰め合わせセットのようにして紹介していきます。

whenにおける新しい使い方

 本連載の最初に紹介するアップデートは、whenにおける新しい使い方です。

whenの確認

 when構文とは、場合分けに使える構文であり、他の言語でのswitch構文と同じものです。例えば、リスト1のような構文です。この例では、1〜10のどれかの整数が格納された変数randの値によって場合分けしています。

[リスト1]when構文の例
val rand = getRandInt()
when(rand) {
  in 8..10 -> println("${rand}点で優です。")
  7 -> println("${rand}点で良です。")
  6 -> println("${rand}点で可です。")
  else -> println("${rand}点で不可です。")
}

 Kotlinでは、このwhen構文が文だけではなく式としても使えます。その場合は、リスト2のようなコードとなります。この例では、randの値によって場合分けされた文字列が、変数msgに格納されます。

[リスト2]when式の例
val rand = getRandInt()
val msg = when(rand) {
  in 8..10 -> "${rand}点で優です。"
  7 -> "${rand}点で良です。"
  6 -> "${rand}点で可です。"
  else -> "${rand}点で不可です。"
}

()内には変数定義式が可能

 when構文において、()に場合分けの元となる変数などを記述します(公式ドキュメントでは、これをsubjectと呼んでいます)。この()内に変数定義が記述できるように、バージョン1.3でアップデートされています。例えば、リスト3のようなコードです。

[リスト3]whenの()内に変数定義を記述した例
when(val rand = getRandInt()) {
  in 8..10 -> println("${rand}点で優です。")
  :
}

 リスト3のように()内で変数を定義するメリットは、その変数(リスト3ならばrand)のスコープがwhenブロック内に限定され、スコープ外、すなわち、whenブロック外から利用される心配がないことです。

lateinitの新しい使い方

 次に紹介するのは、lateinitに関するものです。

lateinitプロパティ

 lateinitは、クラスのプロパティ宣言で利用されてきています。例えば、リスト4のようなコードです。

[リスト4]lateinitプロパティの例
class TimeGenerator {
  private lateinit var _time: LocalTime  // (1)
//  private lateinit var _rand: Int  // (2)
  fun getTimeStr(): String {
    if(!this::_time.isInitialized) {  // (3)
      _time = LocalTime.now()
    }
    return _time.toString()  // (4)
  }
}

 リスト4の(1)のLocalTime型のプロパティ_timeにはlateinitが付与されています。本来ノンナル(Non-Null)のプロパティは、コンストラクタで初期化処理を行う必要があります。もし初期化処理を記述しないならば、ナラブル(Nullable)なプロパティとして定義する必要があります。一方で、コンストラクタ段階、すなわち、インスタンスの生成時には初期化処理が定義できないプロパティもあり、その場合にこのlateinitは非常に便利です。Android開発のアクティビティに定義するプロパティなどで頻出です。

 ただし、lateinitプロパティのデータ型として、プリミティブ型は利用できない点には注意しておいてください。リスト4の(2)のコメントアウトを元に戻すと、コンパイルエラーとなります。

初期化済みかどうかをチェックするisInitialized

 このようなlateinitプロパティは、コンストラクタで初期化する必要がない代わりに、どこか別のメソッド内で初期化処理をしておく必要があります。もちろん、初期化されていない状態でアクセスしようとすると、UninitializedPropertyAccessExceptionが発生してしまいます。

 そのような場合に便利な仕組みが、バージョン1.2で導入されています。それが、リスト4の(3)のisInitializedです。isInitializedは、初期化処理が済んでいるかチェックするプロパティであり、初期化処理が済んでいればtrueとなります。リスト4の(3)では、lateinitプロパティである_timeのtoString()メソッドにアクセスする(4)の前に、isInitializedで初期化済みかのチェックを行い、初期化されていなければLocalTime.now()メソッドで初期化処理を行っています。

 ただし、このisInitializedを利用する場合は、単に_time.isInitializedとはできず、プロパティそのものを参照する「::」を利用し、「this::_time.isInitialized」とする必要がある点には注意しておいてください。

トップレベルプロパティとローカル変数でもlateinitが可能

 isInitializedが導入されたバージョン1.2において、同じく導入されたのが、lateinitの拡張です。これまで、クラスのプロパティでのみ利用できていたlateinitをトップレベルプロパティとローカル変数にも利用できるようになりました。例えば、トップレベルプロパティに導入すると、リスト5のようなコードをファイル直下に記述した場合となります。

[リスト5]lateinitのトップレベルプロパティへの適用例
lateinit var topLevelTime: LocalTime  // (1)
fun getTopLevelTimeStr(): String {
  if(!::topLevelTime.isInitialized) {  // (2)
    topLevelTime = LocalTime.now()
  }
  return topLevelTime.toString()
}

 リスト5の(1)のように、クラス内のプロパティと同様に、トップレベルプロパティ宣言にlateinitを付与できます。そして(2)のように、isInitializedを利用して初期化済みかのチェックも行うことができます。ただし制約があります。まず、ローカル変数にはisInitializedは利用できません。また、トップレベルプロパティで利用する場合は、そのプロパティが宣言された同一ファイル内で利用する必要があり、その場合は、(2)の「::topLevelTime.isInitialized」のように、「::」から始める記述とします。

次のページ
アンダースコアの使い方

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook<個人紹介>WINGSプロジェクト所属のテクニカルライター。Web系製作会社のシステム部門、SI会社を経てフリーランスとして独立。屋号はSarva(サルヴァ)。HAL大阪の非常勤講師を兼務。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/20141 2024/09/24 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング