Kotlinのnullチェックについて

採用はこちら

Kotlinは NullPointerException(NPE)をできるだけ防ぐ設計を持つプログラミング言語です。

Javaでは null によるエラーが頻発しますが、Kotlinでは 型システムでnullを管理する仕組みが組み込まれています。

つまり、Kotlinでは

  • nullを許可する型
  • nullを許可しない型

が明確に区別されています。

目次

Kotlinのnull安全の基本

Kotlinでは型により null 許容が決まります。

val a: String = "Hello"

この型は nullを許可しません

a = null // コンパイルエラー

一方、次のように ? を付けると null を許可します。

val b: String? = "Hello"

この場合

val b: String? = null

も可能です。

つまり基本ルールは次です。

null
String許可しない
String?許可する

nullable型はそのままメソッドを呼べない

nullable型では、直接メンバーアクセスできません。

val name: String? = "Taro"

println(name.length)

これは コンパイルエラーになります。

なぜなら、name が null の可能性があるからです。

この問題を解決するための仕組みが safe call です。

Safe Call(安全呼び出し)?.

safe call は次のように書きます。

name?.length

動作は次の通りです。

name != null → lengthを取得
name == null → 式の結果はnull

val name: String? = null

println(name?.length)

name?.length の評価結果は null になり、それが println に渡されるため null と表示されます。

重要なポイントは

safe call は null を返す

ということです。

Elvis演算子 ?:

nullの場合の代替値を指定する方法です。

val name: String? = null

val length = name?.length ?: 0

println(length)

意味

name?.length が nullなら 0 を返す

つまり

A ?: B

AがnullならB

という意味です。

この演算子はKotlinコードで非常によく使われます。

非nullアサーション !!

!!強制的に非nullとして扱う演算子です。

val name: String? = "Taro"

println(name!!.length)

もし name が null の場合

NullPointerException

が発生します。

つまり

nullable型を強制的にnon-nullとして扱う

ための演算子です。

ただし、この方法は Kotlinのnull安全を無効化するため、実務では なるべく使わない のが基本です。

ifによるnullチェックとSmart Cast

Kotlinではnullチェックをすると、コンパイラが型を推論します。

val name: String? = "Taro"

if (name != null) {
    println(name.length)
}

このブロック内では

name は String として扱われる

これを Smart Cast と呼びます。

ただし注意点があります。

Smart Cast は次のような場合に成立します。

  • ローカル変数
  • 再代入されない val
  • コンパイラが値が変わらないと判断できる場合

mutableなプロパティでは成立しないことがあります。

?.let を使ったnullチェック

Kotlinでは次の書き方がよく使われます。

name?.let {
    println(it.length)
}

これは

nameがnullでない場合だけ実行

という意味です。

内部的には次のような処理に近いです。

if (name != null) {
    println(name.length)
}

ここで重要なのは

let がnullチェックしているのではない

という点です。

nullを回避しているのは

?. (safe call)

です。

Safe Callの連鎖

safe call はチェーンできます。

user?.address?.city

この処理は次のような意味になります。

userがnullなら終了
addressがnullなら終了
cityを取得

Javaで書くと次のようになります。

if(user != null){
    if(user.getAddress() != null){
        return user.getAddress().getCity();
    }
}

Kotlinでは非常に簡潔に書けます。

また、safe callを使った式の結果は通常 nullable型になります

val city: String? = user?.address?.city

requireNotNull と checkNotNull

Kotlinには null をチェックする標準関数があります。

requireNotNull

val name: String? = "Taro"

val result = requireNotNull(name)

println(result.length)

nullの場合

IllegalArgumentException

が発生します。

主な用途は

引数のバリデーション

です。

checkNotNull

val config: String? = "value"

val result = checkNotNull(config)

nullの場合

IllegalStateException

になります。

主な用途

オブジェクトの状態チェック

KotlinでもNullPointerExceptionは起こり得る

Kotlinはnull安全な言語ですが、NPEが完全に無くなるわけではありません。

主な原因は次の通りです。

!! を使用した場合

name!!.length

Javaコードとの相互運用

Javaにはnull許容情報がない場合があるため

platform type

として扱われます。

lateinit未初期化

lateinit var name: String

未初期化のまま使うと

UninitializedPropertyAccessException

が発生します。

外部ライブラリ

Javaライブラリからnullが渡されることがあります。

コレクションとnull

Kotlinではコレクションでもnullの扱いが分かれます。

List<String>

リストも要素もnull不可

List<String?>

要素がnull可能

List<String>?

リスト自体がnull可能

List<String?>?

両方null可能

この違いは実務で重要です。

実務でよく使うnull処理パターン

Safe Call

user?.name

Elvis演算子

val name = user?.name ?: "guest"

let

user?.let {
    println(it.name)
}

ifチェック

if (user != null) {
    println(user.name)
}

まとめ

Kotlinのnull安全の基本は次の通りです。

型でnullを管理

String
String?

safe callでnull回避

?. 

Elvis演算子で代替値

?: 

smart cast

if(x != null)

!! は最後の手段

Kotlinのnull安全は単なる文法ではなく、言語設計の中心的思想です。

これを理解すると、Javaよりも 安全で読みやすいコードを書くことができます

以上、Kotlinのnullチェックについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次