Edit Page

Nullセーフティ(ツアー)

Kotlinでは、nullの値をとる事がある。 プログラムにおけるnullにまつわる問題を防ぐため、 KotlinにはNullセーフティというものがあります。 Nullセーフティは、nullにまつわる潜在的な問題を、実行時では無くコンパイル時に検出します。

Nullセーフティは以下を可能にする機能の組み合わせです:

  • nullの値がプログラムのどこで許容されるかを明示的に宣言
  • null値のチェック
  • null値かもしれないオブジェクトのプロパティや関数の安全な呼び出し(セーフコール)
  • nullが検出された時のアクションの宣言

Nullable型

KotlinはNullable型をサポートしています。Nullable型とはnullの値が入っても良い型というものです。 デフォルトでは、型はnullを受け入れません。Nullable型は明示的に?を型の後ろにつけることで宣言します。

例:

fun main() { // neverNullはString型 var neverNull: String = "これはnullにはなり得ない" // コンパイルエラー neverNull = null // nullable変数はnullableはString型 var nullable: String? = "ここにはnullも格納出来る" // これはOK nullable = null // デフォルトではnullは受け付けない var inferredNonNull = "コンパイラはnullableでは無いと想定する" // コンパイルエラー inferredNonNull = null // notNullはnullを受け付けない fun strLength(notNull: String): Int { return notNull.length } println(strLength(neverNull)) // 18 println(strLength(nullable)) // コンパイルエラー }

lengthStringクラスのプロパティで、 文字列に含まれる文字の数を保持します。

null値のチェック

条件式の中でnullかどうかをチェック出来ます。 以下の例では、describeString()関数のif文で、 maybeStringnullではないか、そして長さが0より大きいかをチェックしています:

fun describeString(maybeString: String?): String { if (maybeString != null && maybeString.length > 0) { return "長さ${maybeString.length}の文字列" } else { return "空かnullの文字列" } } fun main() { var nullString: String? = null println(describeString(nullString)) // 空かnullの文字列 }

セーフコール

null値かもしれないオブジェクトのプロパティに安全にアクセスする為に、セーフコール演算子 ?. が使えます。 セーフコール演算子はオブジェクトがnullの時にはプロパティがnullを返すようにします。 これはnullだった時にエラーが起こるのを防ぐのに有用です。

以下の例で、lengthString()関数はセーフコールを使って、文字列の長さかnullのどちらかを返します:

fun lengthString(maybeString: String?): Int? = maybeString?.length fun main() { var nullString: String? = null println(lengthString(nullString)) // null }

セーフコールはつなげる事(チェイン)が出来ます。その時はプロパティのどれかがnullだったらnullを返す事になります。 例:

  person.company?.address?.country

セーフコール演算子はまた、extension関数やメンバ関数を安全に呼ぶのにも使えます。 この場合、nullチェックは関数の実行をする前に行われます。 もしこのチェックがnull値を検出したら、関数の呼び出しはスキップされnullが返されます。

以下の例では、nullStringnullなので、 .uppercase()の呼び出しはスキップされて、 nullが返されます。

fun main() { var nullString: String? = null println(nullString?.uppercase()) // null }

Elvis演算子を使おう!

Elvis演算子(Elvis operator) ?:を使う事で、null値が検出された時に返すデフォルトの値を提供する事が出来ます。

Elvis演算子の左には、null値かどうかをチェックしたい対象を書きます。 Elvis演算子の右には、null値が検出された時に返したい値を書きます。

以下の例では、nullStringnullなので、lengthプロパティのセーフコールはnull値を返します。 結果として、Elvis演算子は0を返します:

fun main() { var nullString: String? = null println(nullString?.length ?: 0) // 0 }

KotlinにおけるNullセーフティについてのより詳細な情報は、Nullセーフティを参照ください。

練習問題

あなたの手元にはemployeeById関数があります。これは会社の会社員に関するデータベースへのアクセスを提供しています。 残念なことに、この関数はEmployee?型を返します。だから結果がnullな事がありえます。 以上を踏まえて、社員のidが渡されたら給料(salary)を返す関数を書いてください。ただしデータベースに社員が存在しなかったら0を返してください。

data class Employee (val name: String, var salary: Int) fun employeeById(id: Int) = when(id) { 1 -> Employee("Mary", 20) 2 -> null 3 -> Employee("John", 21) 4 -> Employee("Ann", 23) else -> null } fun salaryById(id: Int) = // Write your code here fun main() { println((1..5).sumOf { id -> salaryById(id) }) }
解答例
data class Employee (val name: String, var salary: Int)

fun employeeById(id: Int) = when(id) {
    1 -> Employee("Mary", 20)
    2 -> null
    3 -> Employee("John", 21)
    4 -> Employee("Ann", 23)
    else -> null
}

fun salaryById(id: Int) = employeeById(id)?.salary ?: 0

fun main() {
 println((1..5).sumOf { id -> salaryById(id) })
}

次は何をやるべき?

おめでとうございます!今やKotlinのツアーを無事終了したあなたとしては、Kotlinの人気の使い道のチュートリアルを要チェックです!