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
>>>