KotlinではNull Safetyにあるように、NullableとNon-Nullが定義できる。
var nullable: String?
var nonNull: String
これはコンパイル時にNullチェックができ、NPEを未然に防げる。
nullable.length // コンパイルエラー
nonNull = null // コンパイルエラー
これだけではなくNull-Safety and Platform Typesにあるように、両方の状態を併せ持つ定義もある。
以下のようなJavaクラス定義があったとする。
JavaObject.java
public class JavaObject {
public String string;
@Nullable public String nullableString;
}
Javaコードから返却される型はT!
の様に表現され、T
またはT?
の意味になる。
val javaObject = JavaObject()
var either = javaObject.string
両方の状態を持てるため、アクセスしてもコンパイルエラーとはならないが、NPEが発生する可能性はある。
either.length // NPEが発生するかもしれない
null
を代入することも可能だが、null
を代入した直後はT?
になるため、アクセスするとエラーとなる。
either = null
either.length // コンパイルエラー
明示的にT!
を定義することはできない。
そのため、Javaのメソッドをオーバーライドするときは、引数を明示しなくてはならない。
var either: String! // 不可能
override fun onCreate(savedInstanceState: Bundle?) {}
override fun onSaveInstanceState(outState: Bundle) {}
Javaのメソッドをオーバーライドしたときの引数は、指定を間違えるとNPEが発生する可能性がある。
override fun getView(position: Int, convertView: View, parent: ViewGroup) {
// throws NPE (convertView is null)
}
(メジャーな)@NonNull
や@Nullable
アノテーションはコンパイル時にチェックしてくれる。
javaObject.nullableString.length // コンパイルエラー
まとめ
- Kotlinは基本的にNull Safetyだが、Javaが絡むとそうとはいえない。
- Java側は積極的にアノテーションを付けるようにする。
- Calling Java code from Kotlinをよく読む。