Null safety
Kotlinでは、null
値を扱うことができます。Kotlinは、何かが不足している場合やまだ設定されていない場合にnull
値を使用します。 コレクションの章で、マップに存在しないキーを持つキーと値のペアにアクセスしようとした際に、Kotlinがnull
値を返す例をすでに見ています。このようにnull
値を使用することは有用ですが、コードがそれらを処理する準備ができていない場合、問題が発生する可能性があります。
プログラムでのnull
値による問題を防止するために、Kotlinにはnull safetyが備わっています。Null safetyは、実行時ではなく、コンパイル時にnull
値に関する潜在的な問題を検出します。
Null safetyは、以下のことを可能にする機能の組み合わせです。
- プログラムで
null
値が許容される場合を明示的に宣言する。 null
値をチェックする。null
値を含む可能性のあるプロパティや関数に対して安全な呼び出しを使用する。null
値が検出された場合に実行するアクションを宣言する。
Null許容型
KotlinはNull許容型をサポートしており、これにより宣言された型がnull
値を持つ可能性を許容します。デフォルトでは、型はnull
値を受け入れることはできません。Null許容型は、型宣言の後に明示的に?
を追加することで宣言されます。
例:
fun main() {
// neverNull has String type
var neverNull: String = "This can't be null"
// Throws a compiler error
neverNull = null
// nullable has nullable String type
var nullable: String? = "You can keep a null here"
// This is OK
nullable = null
// By default, null values aren't accepted
var inferredNonNull = "The compiler assumes non-nullable"
// Throws a compiler error
inferredNonNull = null
// notNull doesn't accept null values
fun strLength(notNull: String): Int {
return notNull.length
}
println(strLength(neverNull)) // 18
println(strLength(nullable)) // Throws a compiler error
}
length
は、文字列内の文字数を含むStringクラスのプロパティです。
Null値のチェック
条件式内でnull
値の存在をチェックできます。次の例では、describeString()
関数には、maybeString
がnull
ではなく、そのlength
が0より大きいかどうかをチェックするif
ステートメントがあります。
fun describeString(maybeString: String?): String {
if (maybeString != null && maybeString.length > 0) {
return "String of length ${maybeString.length}"
} else {
return "Empty or null string"
}
}
fun main() {
val nullString: String? = null
println(describeString(nullString))
// Empty or null string
}
安全な呼び出しの使用
null
値を含む可能性のあるオブジェクトのプロパティに安全にアクセスするには、安全な呼び出し演算子?.
を使用します。安全な呼び出し演算子は、オブジェクトまたはアクセスされたプロパティのいずれかがnull
の場合にnull
を返します。これは、null
値がコード内でエラーを引き起こすのを避けたい場合に役立ちます。
次の例では、lengthString()
関数は安全な呼び出しを使用して、文字列の長さまたはnull
のいずれかを返します。
fun lengthString(maybeString: String?): Int? = maybeString?.length
fun main() {
val nullString: String? = null
println(lengthString(nullString))
// null
}
安全な呼び出しはチェーン化できるため、オブジェクトのプロパティに
null
値が含まれている場合、エラーをスローせずにnull
が返されます。例:kotlinperson.company?.address?.country
安全な呼び出し演算子は、拡張関数やメンバー関数を安全に呼び出すためにも使用できます。この場合、関数が呼び出される前にnullチェックが実行されます。チェックがnull
値を検出すると、呼び出しはスキップされ、null
が返されます。
次の例では、nullString
がnull
であるため、.uppercase()
の呼び出しはスキップされ、null
が返されます。
fun main() {
val nullString: String? = null
println(nullString?.uppercase())
// null
}
エルビス演算子の使用
null
値が検出された場合に返すデフォルト値を、エルビス演算子?:
を使用して提供できます。
エルビス演算子の左側には、null
値をチェックする対象を記述します。 エルビス演算子の右側には、null
値が検出された場合に返す値を記述します。
次の例では、nullString
がnull
であるため、length
プロパティにアクセスするための安全な呼び出しはnull
値を返します。その結果、エルビス演算子は0
を返します。
fun main() {
val nullString: String? = null
println(nullString?.length ?: 0)
// 0
}
Kotlinのnull safetyに関する詳細は、Null safetyを参照してください。
練習問題
演習
会社の従業員データベースにアクセスできるemployeeById
関数があります。残念ながら、この関数はEmployee?
型の値を返すため、結果がnull
になる可能性があります。あなたの目標は、従業員のid
が提供されたときにその従業員の給与を返す関数を記述することです。従業員がデータベースに見つからない場合は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) })
}