KotlinはJavaに比べるとnullの扱いが特徴的である。 Javaのオブジェクト型の変数は基本的に全てNullableであるが、 Kotlinの場合は明示的に?を指定しない限りはnullを格納することができない。 例えばKotlinのそれぞれの型はJavaでは以下のような記載となる。
種別 | Kotlin | Java |
---|---|---|
非null | var:String s | @NotNull String s; |
nullable | var:String? s | @Nullable String s; |
非nullの変数にnullを格納することはできず、例えば以下のようなコードはビルド時にコンパイルエラーとなる。
fun main(args: Array<String>) { val i:Int = null; println(i); }
fun main(args: Array<String>) { val i:Int? = null; println(i); }
非null型の場合、当然だがNPEを回避するようなコードは不要である。 以上のようにJavaの場合はアノテーションを付けることで静的解析を行うが(あるいは人間がただ頑張るか)、 Kotlinの場合は言語レベルでケアする。
Nullable型を扱う場合は ?. や ?: の演算子を使用する。
val b:String? = "hello" println(b?.length ?: -1) // 5 val a:String? = null println(a?.length ?: -1) // -1
Nonnull型からNullable型への変換はあまり気にする必要がない。
val v:Int = 1 val i:Int? = v
Nullable型からNonnull型への代入はひと手間必要である。
fun main(args: Array<String>) { val v:Int? = 1 val i:Int = v }
fun main(args: Array<String>) { val v:Int? = 1 val i:Int = v!! }
fun main(args: Array<String>) { val v:Int? = null val i:Int = v!! }
fun main(args: Array<String>) { val v:Int? = 1 val i:Int = v ?: 0 }
Nonnull型の関数呼び出しはぬるぽが起きることはないが、Nullableの場合は気にする必要がある。 Nullable の関数呼び出しの場合、 ?. (safe call) の演算子を使用する。
val i:Int? = null i?.let { println(it) } // 実行されない
val v: Int? = a as Int
val v: Int? = a as? Int
val nullableList: List<Int?> = listOf(1, 2, null, 4) val intList: List<Int> = nullableList.filterNotNull()
?.がnullの場合にletを処理せずにnullを返すため、?: nullの場合を処理を記載できる。
>>> var v:String? = null >>> var s:String = v?.let { it.toUpperCase() } ?: "" >>> println(s) >>> var v:String? = "hoge" >>> var s:String = v?.let { it.toUpperCase() } ?: "" >>> println(s) HOGE >>>