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)