Kotlinのnull安全について

採用はこちら

Kotlinの null安全(Null Safety) は、Javaなどで頻発してきたNullPointerException(NPE)を「実行時」ではなく「設計とコンパイル時」に防ぐ ための、言語設計の中核となる仕組みです。

単なる便利構文の集合ではなく、

「nullを許可するかどうかを型で明示し、危険な操作をコンパイル時に排除する」

という明確な思想に基づいています。

目次

Kotlinでは「nullを型で制御する」

Kotlin最大の特徴は、nullを許容するかどうかを型として区別する点にあります。

非null型(デフォルト)

var name: String = "Kotlin"
// name = null // コンパイルエラー
  • Stringnullを一切許容しない型
  • nullを代入しようとすると コンパイル時点でエラー

このため、純粋なKotlinコード内では「うっかりnullが入る」ことが起きません。

null許容型(Nullable Type)

var nickname: String? = "Kot"
nickname = null // OK
  • ? を付けた型のみが null を保持できる
  • StringString?完全に別の型

Kotlinではこの区別が強制されるため、nullを扱う箇所がコード上で明確に可視化されます。

null許容型は「そのまま使えない」

val length = nickname.length // コンパイルエラー

nullの可能性がある値に対して、Kotlinは 直接のプロパティ・メソッドアクセスを許可しません

これが「null安全」の第一の防波堤です。

セーフコール演算子 ?.

null許容型を安全に扱う基本が セーフコール演算子 です。

val length = nickname?.length

挙動

  • nickname == null → 結果は null
  • nickname != nulllength を返す
  • NPEは発生しない

重要な点として、結果の型は Int?(nullable)になる ことを理解しておく必要があります。

エルビス演算子 ?:(null時の代替処理)

nullableな結果に対して、nullだった場合の処理を明示するのがエルビス演算子です。

val length = nickname?.length ?: 0
  • null → 0
  • 非null → 実際の length

?: の右側は単なる値だけでなく、も書けます。

val name = nickname ?: error("nickname is required")

このため、「nullなら例外」「nullならreturn」などの制御フローにも頻繁に使われます。

非nullアサーション演算子 !!(最終手段)

val length = nickname!!.length
  • 「ここは絶対にnullではない」と開発者が宣言する演算子
  • nullだった場合は NPE系の例外が即発生

評価

  • 安全性を放棄するため多用はNG
  • Java移行コードや、明確な不変条件がある場合のみ限定使用

Kotlinで !! が頻出するコードは、設計段階でnullを適切に扱えていない可能性が高い と判断されます。

let による安全なスコープ処理

nullでない場合のみ処理を行いたいときに多用されるのが let です。

nickname?.let {
    println(it.length)
    println(it.uppercase())
}

特徴

  • nullの場合はブロックが実行されない
  • it確実に非null
  • スコープを限定でき、変数汚染を防げる

UI更新、ログ出力、副作用処理との相性が非常に良い構文です。

スマートキャスト(Smart Cast)

Kotlinは nullチェック後に自動で型を絞り込む 機能を持っています。

if (nickname != null) {
    println(nickname.length) // Stringとして扱われる
}

注意点(重要)

スマートキャストが成立するには条件があります。

  • 対象が val(不変) である
  • あるいは、コンパイラが「この変数は途中で変更されない」と証明できる場合

var やカスタムgetterが絡む場合、スマートキャストされないケースもあるため注意が必要です。

lateinit と null安全

lateinit var userName: String

特徴

  • nullを許容しない
  • 初期化を後回しにできる
  • var にしか使えない

注意点

println(userName) // 初期化前だと例外
  • UninitializedPropertyAccessException が発生
  • null安全とは 別軸の仕組み

主にDI・Android・テスト用途で使われます。

Javaとの相互運用とプラットフォーム型

Java由来の値は、Kotlinでは プラットフォーム型(例:String! になる場合があります。

val text = javaMethod() // String!
  • nullかもしれないし、違うかもしれない
  • Kotlinが安全性を保証できない型

補足(重要)

Java側に @Nullable / @NotNull などの
nullabilityアノテーションが付いている場合、
Kotlinは String? / String として推論できます。

つまり、Java連携は「常に危険」ではなく、設計次第で安全性を高められます。

KotlinでもNPEが起きる主なケース

Kotlinでも、以下のような「抜け道」では例外が発生します。

  • !! の使用
  • Java相互運用による想定外のnull
  • lateinit の未初期化アクセス
  • 明示的にNPEを投げた場合

ただし、純粋なKotlinコードだけで正しく設計すれば、NPEはほぼ排除できます。

実務でのベストプラクティス

  • 非null型を基本に設計する
  • nullは「仕様上必要な場合のみ許容」
  • !! は最後の手段
  • ?. + ?: + let を適切に組み合わせる
  • Java連携部分は特に慎重に扱う

まとめ

Kotlinのnull安全は、

nullを「扱う技術」ではなく、「発生させない設計」

を実現するための仕組みです。

  • nullを型で明示
  • 危険な操作をコンパイル時に排除
  • コード量とバグを同時に減らす

この考え方を正しく理解すると、Kotlinらしい、堅牢で読みやすいコード が自然に書けるようになります。

以上、Kotlinのnull安全についてでした。

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

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