読者です 読者をやめる 読者になる 読者になる

算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

Kotlin M9で追加されたPlatform Typeの話

Kotlin

Kotlinマイルストーン9がリリースされた!

M9 is here! | Project Kotlin

これについて。

Javaメソッドの戻り値の型がPlatform Typeって呼ばれる特殊な感じになったらしい。

今まではJavaメソッドの戻り値の型は@NotNullなどで明示していない限り、すべてNullableとして扱われていた。

// Java
public static Integer id(final Integer value) {
    return value;
}
// M9より前
val a = id(5)       // aの型はInt?
println(a.plus(2))  // コンパイルエラー

M9では上記の変数aの型がPlatform Typeとなってこうなる。

// M9
val a = id(5)       // aの型はInt!
println(a.plus(2))  // => 7

このコードはコンパイル可能で、実行時にもエラーは起こらない。 コンパイルがうまく行くのはaがPlatform Typeとして扱われるからで、実行時にエラーが起こらないのはanullでないから。Platform TypeのIntなのでaInt!型となる、らしい。

では、nullの場合はどうなるのか。

val b = id(null)    // bの型はInt!
println(b.plus(2))  // ここで例外

先ほどの例と同様にコンパイルは通る。しかし実行するとb.plus(2)の箇所で例外を投げる。

Exception in thread "main" java.lang.NullPointerException
    at sample.SamplePackage$Main$6051fa33.main(Main.kt:8)
    at sample.SamplePackage.main(Main.kt:1)
・・・

ぬるぽ!Kotlinでぬるぽった!!

ぬるぽ怖い。なので型を明示する。

val b: Int? = id(null) // bの型はInt?
println(b.plus(2))     // コンパイルエラー

型を明示することでPlatform Type(Int!)を使わずにNullable(Int?)として変数を扱えるようになる。

逆にNotNullを表明することもできる。

val a: Int = id(5)  // aの型はInt
println(a.plus(2))  // => 7

さらにnullが返ってくるにも関わらずNotNull型として宣言できちゃう。

val b: Int = id(null) // ここでNullPointerException
println(b.plus(2))

コンパイルは通る。bInt型として扱われるのでb.plus(2)も問題なくコンパイルされる。 しかし今回の場合bnullなのでval b: Int = id(null)のタイミングでNPEが投げられる。コンパイルして生成されたバイトコードを見るとNullチェックが差し込まれているのがわかる*1

このPlatform TypeによりJavaコードの呼び出しが手軽になった。けれど簡単にNullPointerExceptionが起こるようになってしまったと思う。。*2

*1:この例のようなIntegerだとNullチェックはされていなくて単にintValue()が呼び出されているだけだった

*2:まぁ今までもNPEは起こせたんだけど、よりNPEが起こる機会が増えた