サイトロゴ

Enjoy Creating
Web & Mobile Apps

MENU BOX
WEB
MOBILE
OPEN

ホーム

 > 

 > 

Kotlinにおけるnullの基本(セーフコール・エルビス演算子)

Kotlinにおけるnullの基本(セーフコール・エルビス演算子)

この記事にはプロモーションが含まれています。

プログラミングを理解する上で、null やその取扱いを学ぶことはかなり重要で、学習項目の中でも優先順位が高い項目であると言えます。

というのも、『やっかいなエラーの原因はだいたいnullのせい』…といっても過言ではないぐらい、nullは様々な問題の原因になり得る特殊な値だからです。

ということで今回は、Kotlinにおけるnullの基本についてご紹介します!

この記事を読むことで分かること
  • ・Kotlinにおけるnullの基本
  • ・null安全(Null Safety)
  • ・セーフコール
  • ・エルビス演算子

– 目次 –

そもそもnull(ヌル)って?

null というのは、『無(値が決まっていない・決められない状態)』であることを示す特別な値です。(細かい概念等は、プログラミング言語によって異なる場合があります)

『無』と言っても、数値の0(ゼロ)や、空の文字列("")とは異なる点に注意が必要です。

nullは0でも空の文字列でもないことを表すイメージ図

0(ゼロ)は、あくまで数値が0で表される状態であることを示すものであり、値が決まっていない(決められない)状態というわけではありません。

たとえば、ゲームアプリを作っていて、プレイヤーの所持金の初期値を0(ゼロ)に設定するとしましょう。

このとき、所持金の初期値が決められないから0にするわけではなく、明確に『所持金の初期値は0とする』ことを決めたからこそ、0を指定するわけですよね。

値が未決定の場合に、とりあえず0を指定しておくようなケースもありますが、『0=値が決められない場合に限定して使われる』というものでは決してありません。

空の文字列("")に関しても、これは『テキストを代入できるところを確保している』というような状態であり、言い換えれば、何らかのテキストが代入されることが分かりきっていることになります。

こちらもやはり、nullが意味するような、値が全く決められない『無の状態』とは異なります。

繰り返しになりますが、 null = 無(値が決められない)状態を示す特殊な値 ということをまずしっかりイメージとして定着させておくことが大切です。

そんな null は様々な場面で使用されますが、主に次のような場面で使われることが多いです。

  • (1)外部APIから返されるデータのうち、該当データがなかった場合に null が返される
  • (2)変数の初期値を決めておくことができない場合に、初期値を null にしておく

この記事では、(2)のケースを想定して解説を進めていきます。

たとえば、毎日その日に使ったお金を記録するお小遣い帳アプリをイメージしてみてください。

このとき、初期値が0(ゼロ)では少しマズイですよね。

というのも、お金を使わない(入力値が0である)日も当然あり得るので、初期値が0では未入力状態なのか、入力した上で0なのかが判別できないためです。

基本的に、null を使わずに済むならその方が良いのですが、このような場合は null をうまく活用した方が状態が分かりやすくなります。

次のステップでは、Kotlinでnullを扱うシンプルなコードを紹介しながら、null への理解を深めていきたいと思います。

    POINT!
  1. ・nullは、値が決まっていない(決められない)”無”の状態を表す特別な値!
  2. ・nullは、0(ゼロ)でも、空の文字列でもない!
  3. ・API連携で返されるデータにnullが含まれているケースの他、どうしても初期値が決められない場合にnullを利用するケースがある!

Kotlinはnull安全を備えている

Kotlinの特徴の一つに、『null安全(Null Safety)』と呼ばれるものがあります。

これは簡単に言ってしまえば、『nullは特別な値で様々なエラーの原因になっちゃうので、nullの扱いには制限をかけますよ & 値がnullかどうか厳密なチェックを行いますよ』…といった仕組みのことです。

Kotlinにおけるnull安全に関しては、次のような機能(制限)があります。

  • ・変数の型が指定されている場合、nullは通常の手段ではその変数に代入できない
  • ・基本的に、nullの可能性がある変数に対しては、その可能性が残されたままメソッドやプロパティを利用したりすることができない

このあたりは、実際にコードを書いて実行してみた方がわかりやすいと思うので、さっそく例を見ていきましょう。

下のコードは、Int型の変数に null を代入しようとしているので、Kotlinのnull安全機能に引っかかり、コンパイルエラーになります。

Kotlin

var expenses:Int = null // error

では、絶対にこの変数 expenses には null を代入できないのかというと、そういうわけではありません。

データの型に ? マークを付け加えることで、null許容にする(= null を代入可能にする)ことができます。

Kotlin

var expenses:Int? = null // OK

このように、開発者が意図的にnull許容に設定しない限り、不意に null が代入されてしまうことがないことが、プログラムの安全性の向上に繋がっています。

また、Int型には様々なメソッドが用意されていますが、値が null の可能性が残されているままで、そういったメソッドを実行することはできません。

たとえば、Int.equals() という、数値が他のある数値と等しいかどうかを調べるためのメソッドをそのまま使おうと思っても、エラーになってしまいます。

Kotlin

var expenses:Int? = null // OK

val isEqual = expenses.equals(100) // error
println(isEqual)

この問題に対する解決策は、次のステップでご紹介していきます。

    POINT!
  1. ・Kotlinは、null安全(Null Safety)を備えている!
  2. ・?マークを使って意図的に指定しない限り、基本的にnullを代入することはできない!
  3. ・nullの可能性がある値に対し、そのメソッドやプロパティにそのままアクセスすることは基本的にできない!

nullの可能性がある変数のメソッドを利用する

nullの可能性がある変数のメソッドやプロパティを利用する方法でオーソドックスなのが、『条件分岐でnull の可能性を否定する』という方法です。

次のように、if文の条件として、変数が null ではないことを指定すれば、そのブロック内では変数が null ではないことが決定されるので、エラーにはなりません。

Kotlin

var expenses:Int? = null // OK
    
if(expenses != null) {
    val isEqual = expenses.equals(100)
    println(isEqual)
} else {
    println("value is null")
}

// Output: value is null

上のサンプルの場合、if文の条件を満たさないためifブロックはそもそも実行されず、elseブロックの処理のみが実行されることで、エラーが回避されています。

また、セーフコール(Safe calls)と呼ばれる方法を用いることでも、null の可能性がある変数のメソッド等を利用することができます。

セーフコールを利用するには、.? 演算子を使います。

Kotlin

var expenses:Int? = null // OK

val isEqual = expenses?.equals(100)
println(isEqual) // null

上の結果から分かるように、セーフコールを利用してメソッド等にアクセスした結果、前提となる変数が null であった場合は null が返されるようになっています。

null の可能性がある変数のメソッドを利用 → その結果も null かもしれないので、再びセーフコール演算子で次のメソッドを利用 …というふうに、下のようにチェーンのような形になることもよくあります。

propA?.methodA()?.methodB()?.propB

やや強引ですが、今回の例を使ってセーフコールのチェーンを表現した例が下です。

Kotlin

var expenses:Int? = null // OK

val isEqual = expenses?.equals(100)?.compareTo(true)?.toString()?.length
println(isEqual) // null

変数 expensesnull なので、結局、null が返されていることが確認できますね。

また、プログラムコード上では null の可能性があるとされているが、開発者が絶対に null の可能性はないと断定できる場合、!! 演算子を使って、強制アンラップすることも可能です。

Kotlin

var expenses:Int? = 100

val isEqual = expenses!!.equals(100)
println(isEqual) // true

上のサンプルの場合、null許容にしているものの、実際に代入されている値は 100 であり、それ以降、他の値は変数に代入されていません。

よって、変数 expenses はnull許容値ではあるものの、実質的に null の可能性はありません。

このような場合であれば、!! 演算子で強制アンラップしてしまっても大丈夫です。

ですが、null の可能性が残されている場合、null参照によるエラーの原因となってしまう恐れがあるので、できる限り強制アンラップは避けた方が無難だと言えます。

    POINT!
  1. ・nullの可能性が残される場合、条件分岐でnullの可能性を除去すると処理できる!
  2. ・セーフコール(.?)を利用することで、安全にnullの可能性がある値のメソッドやプロパティにアクセスできる!
  3. ・100%nullではないと断言できる場合、!! 演算子で強制アンラップすることも可能!

エルビス演算子

これまでKotlinにおける null の扱いの基本について解説してきましたが、最後に『エルビス演算子』と呼ばれる、便利な記法をご紹介します。

null の可能性がある場合、基本的にはif文で条件判定を行い、null の可能性を消去することが求められますが、if文だとどうしてもコードの行数が増えて記述量が多くなってしまいます。

セーフコール演算子(?.)を使えばif文を書かずに済みますが、セーフコールのみでは値が null だった場合の処理を追加できません。

この問題を解決してくれるのが、エルビス演算子( ?: )です。

エルビス演算子を使った構文は下のようになります。

null かもしれない値 ?: 値がnullだった場合の処理

expensesnull ではなかったらその値を、null ならメッセージテキストを出力する関数を、エルビス演算子を使って定義した例が下です。

Kotlin

var expenses:Int? = null
    
fun printExpenses() {
    println(expenses ?: "value is null")
}
    
printExpenses()
   
// Output: value is null

当然、null でない値を指定すれば、その値が出力されます。

Kotlin

var expenses:Int? = 100
    
fun printExpenses() {
    println(expenses ?: "value is null")
}
    
printExpenses()
   
// Output: 100

ちなみに、エルビス演算子の名前の由来は、[ ?: ] このマークがエルビス・プレスリーの髪型に似ているかららしいのですが…筆者としては、よくわかりませんでした。笑

おそらく、?マークの膨らんだ部分がリーゼントヘアーの膨らみの部分を表しているのではないかと思いますが、違ったらすいません💦

ともかく、以上がKotlinにおける null の基本です。

Kotlin + Jetpack Compose でシンプルなAndroidアプリを開発するぐらいであれば、これぐらいの基礎知識でも十分です。

Kotlinはnull安全を備えているので、特別にnullを意識しなくても、安全にアプリ開発を行えるのはありがたいポイントですね!

    POINT!
  1. ・エルビス演算子を利用することで、値がnullだった場合の処理を柔軟に設定できる!
  2. ・エルビス演算子は、[ ?: ] で表す!
  3. ・シンプルなAndroidをアプリ開発を行う上では、nullに関してはこれぐらいの基礎知識でもOK!

« »

カテゴリーリンク

著者について- author profile -

ROYDOプロフィール写真
Michihiro

モバイルアプリ(iOS・Android)ディベロッパー&デザイナー

これまでに、可読性の高いカラーパターンを自動で生成するアプリや、『第3火曜日』といった形式で通知をスケジュールできるアプリなどを制作。

サブでWebデザイン・フロントエンドエンジニアとしても活動しています。

📝ツール・言語:JavaScript/React Native/Kotlin/Android Studio/Swift/SwiftUI

🎓資格:応用情報技術者/基本情報技術者/ウェブデザイン技能検定3級

Twitterアイコン Instagramアイコン