Skip to content

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許容型は、型宣言の後に明示的に?を追加することで宣言されます。

例:

kotlin
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()関数には、maybeStringnullではなく、そのlengthが0より大きいかどうかをチェックするifステートメントがあります。

kotlin
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のいずれかを返します。

kotlin
fun lengthString(maybeString: String?): Int? = maybeString?.length

fun main() { 
    val nullString: String? = null
    println(lengthString(nullString))
    // null
}

安全な呼び出しはチェーン化できるため、オブジェクトのプロパティにnull値が含まれている場合、エラーをスローせずにnullが返されます。例:

kotlin
  person.company?.address?.country

安全な呼び出し演算子は、拡張関数やメンバー関数を安全に呼び出すためにも使用できます。この場合、関数が呼び出される前にnullチェックが実行されます。チェックがnull値を検出すると、呼び出しはスキップされ、nullが返されます。

次の例では、nullStringnullであるため、.uppercase()の呼び出しはスキップされ、nullが返されます。

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

エルビス演算子の使用

null値が検出された場合に返すデフォルト値を、エルビス演算子?:を使用して提供できます。

エルビス演算子の左側には、null値をチェックする対象を記述します。 エルビス演算子の右側には、null値が検出された場合に返す値を記述します。

次の例では、nullStringnullであるため、lengthプロパティにアクセスするための安全な呼び出しはnull値を返します。その結果、エルビス演算子は0を返します。

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

Kotlinのnull safetyに関する詳細は、Null safetyを参照してください。

練習問題

演習

会社の従業員データベースにアクセスできるemployeeById関数があります。残念ながら、この関数はEmployee?型の値を返すため、結果がnullになる可能性があります。あなたの目標は、従業員のidが提供されたときにその従業員の給与を返す関数を記述することです。従業員がデータベースに見つからない場合は0を返します。

kotlin
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) })
}
解答例
kotlin
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) })
}