Null安全、ぬるぽバイバイ (Android Kotlin)



Kotlin の基礎を学んだので、今回はNull安全についてまとめてみる。
Javaでは、ぬるぽ (NullPointerException) が許されているが、Kotlinではぬるぽにならないような仕組みでできている。オブジェクトが、nullであり得るか否かを明確に区別するということだ。



スマートキャスト


Nullableな変数を自動的にNotNullへキャストしてくれる。

val x:Int? = "3".toInt()
val y:Int? = "2".toInt()

if (x == null || y == null) {
	return
}

println(x * y) // ここではx、yはNotNullとなっている


なんと、型に対してもスマートキャストは働く。
下のコードの if (obj !is String) return null に注目。

引数objはAny型で渡されたが、いつの間にかobj.lengthというStringクラスのメソッドが使える用になっている。これは if (obj !is String) return nullでのチェック以降は、自動的にStringクラスにキャストされたということだ。

fun getStringLength(obj: Any): Int? {
    if (obj !is String) return null // `!is` は `is`の否定形
    return obj.length
}


もちろん、if文だけでなくwhen文でも使える。xの型によって処理を分けられるのだ。

when (x) {
    is Int -> // xはInt型にキャストされている
    is String -> // xはString型にキャストされている
    is Hoge -> // xはHoge型にキャストされている
    is Fuga -> // xはFuga型にキャストされている
    else -> // xはその他の型にキャストされている
}



エルビス演算子


エルビス演算子 ?: を使えば、nullであった場合のデフォルト値を渡すことができる。
次のように使えるだろう。

val files = File("Hoge").listFiles()
println(files?.size ?: "ファイルが空です")


firstOrNull()は文字列の頭文字を返すメソッドだ。nullだったらエルビス演算子以降の空文字を返すことになる。

val email = "hoge@fuga.xxxxx"
println(email.firstOrNull() ?: "")


?: throw IllegalStateException("Email is missing!")のように、例外を投げて強制終了させることだってできる。

val values = mapOf<String, String?>("email" to null)
val email:String? = values["email"] ?: throw IllegalStateException("Email is missing!")

if (email != null) {
	println(email)
}


上記のような例外をスローさせたい場合には、エルビス演算子ではなく requireNotNull というのも使うことができる。

var fuga:String? = null
var hoge: String = requireNotNull(fuga, {
    fuga = "fuga"
    "${fuga} は nullなわけがない"
})

ここでは第二引数にラムダ式で、例外時のメッセージを渡すようになっている。


安全呼び出し


オブジェクトがnullでなかったら、メソッドを実行したい場合はあるだろう。例えばデリゲートパターンだ。Swiftでは良くやるが、Kotlinでも同じように書くことができる。

public var delegate:Hoge? = null

...

delegate?.someMethod() // delegateがnull出ない場合のみ実行される。



関数letと組み合わせると次のような表現も可能だ。オブジェクトがnullでない場合、letに処理を任せる といったイメージだ。

val value = null
value?.let {
	println("valueがnullでなければここが実行される")
}


let内のラムダ式では、itが使える。エルビス演算子と組み合わせれば、次のように簡潔に表現できる。

val hoge:String? = "ほげほげ"
val fuga = hoge?.let { it + " ふがふが" } ?: ""
println(fuga) //=> ほげほげ ふがふが



Booleanだってnullableになりたい!


たしか、SwiftだとBoolはオプショナル型(nil)にはなれなかったはず。
Kotlinなら次のように、Boolean値がオプショナル型になることができる。

val b: Boolean? = true
if (b == true) {
	println("b は true")
} else {
	println("b は false か null である")
}





参考


Basic Syntax (Kotlin Basic Syntax)
Idioms (Kotlin Basic Syntax)




関連記事


非同期 & ネットワーク処理
はじめてRetrofitを使ってみる (Android Kotlin)
非同期処理でCoroutine(コルーチン)を使ってみる (Android Kotlin)
OkHttpでHTTP通信 (Android Kotlin)
スレッド処理 (Android Kotlin)

View & レイアウト
リサイクラービューを使ってリスト表示 (Android Kotlin)
角丸表現 (Android Kotlin)
onSaveInstanceStateで画面回転時の状態の保存と復元 (Android Kotlin)
ListViewを簡単なモデルで理解しよう (Android Kotlin)
バネアニメーション (Android Kotlin)
startActivityForResultを使ってみる (Android Kotlin)
ActivityとFragmentの連携を理解する (Android Kotlin)
DataBinding機能を使ってみる (Android Kotlin)
タッチイベントのフック (Android Kotlin)
DialogFragmentを使ったダイアログの表示 (Android Kotlin)

サウンド
これってSoundPoolのバグ?(Android Kotlin)
SoundPoolを使ってゲームの効果音を再生する (Android Kotlin)

データ & オブジェクト
Kotlinでオブジェクト(object)の動作確認
データクラスとタプル (Android Kotlin)
Null安全、ぬるぽバイバイ (Android Kotlin)




あなたにおすすめ