Java経験者のKotlin Nullableとlet
Java経験者がKotlinを学習していたときに躓いたポイントをメモしておきます。今回は、Null許容型について。
Nullable
Kotlinのコードを見ているとやけに「?」が多いなと思ったらNull許容型関連のキーワードのようです。
こちらが参考になりました。
Null safety
例えばString型のオブジェクトにnullを入れようとするとコンパイル時にエラーになります。
- fun main() {
- var s: String = "symfo"
- s = null
- println(s)
- }
Null cannot be a value of a non-null type 'kotlin.String'.
nullを許容したい場合は、型名の後に「?」を付けます。
- fun main() {
- var s: String? = "symfo"
- s = null
- println(s) // null
- }
実行結果は「null」と表示されます。
String?に対してlengthで文字列長を取得して見るとコンパイルエラーになります。
- fun main() {
- var s: String? = "symfo"
- println(s.length)
- }
Only safe (?.) or non-null asserted (!!.) calls are allowed
変数名の後に「?」を付けてやると長さが取得できます。
- fun main() {
- var s: String? = "symfo"
- println(s?.length) // 5
- }
sがnullの場合、lengthは評価されず結果はnullとなります。
- fun main() {
- var s: String? = "symfo"
- s = null
- println(s?.length) // null
- }
Elvis operator
nullの場合は文字列長を0としたい場合、こんなよくあるコードになります。
- fun main() {
- var s: String? = null
- val l : Int = if (s != null) s.length else 0
- println(l) // 0
- }
この場合、エルビス演算子「?:」が便利です。
- fun main() {
- var s: String? = null
- val l : Int = s?.length ?: 0
- println(l) // 0
- }
評価値がnullでない場合はその値を、nullの場合は演算子以降の式を評価します。
これを利用して、値の代入以外にnullの場合は関数をreturnしたり、エラーを発生させたりも可能です。
- fun foo(node: Node): String? {
- // node.getParent()がnullを返したらリターン
- val parent = node.getParent() ?: return null
- // node.getName()がnullならエラーをスロー
- val name = node.getName() ?: throw IllegalArgumentException("name expected")
- }
Not-null assertion operator
nullであることをチェックせず強制的に実行する場合は、変数名の後に!!を付与します。
- fun main() {
- var s: String? = "Symfo"
- println(s!!.length) // 5
- }
値がnullの場合は、見慣れたNullPointerExceptionが発生します。
- fun main() {
- var s: String? = null
- println(s!!.length) // error
- }
Exception in thread "main" java.lang.NullPointerException
値のキャストにも利用できます。
- fun main() {
- var s: String? = "Symfo"
- var s2: String = s!!
- println(s2.length) // 5
- }
Let function
letを使用すれば、値がnullでないときのみ処理を実行することができます。
例えばこんな処理。
- fun main() {
- val listWithNulls: List<String?> = listOf("Kotlin", null, "Symfo")
- for (item in listWithNulls) {
- if (item != null) println(item) // Kotlin, Symfo
- }
- }
letを使用して、以下のように記載できます。
- fun main() {
- val listWithNulls: List<String?> = listOf("Kotlin", null, "Symfo")
- for (item in listWithNulls) {
- item?.let {
- println(item) // Kotlin, Symfo
- }
- }
- }
itも使用するとこんな感じになりました。
- fun main() {
- val listWithNulls: List<String?> = listOf("Kotlin", null, "Symfo")
- for (item in listWithNulls) {
- item?.let {
- println(it) // Kotlin, Symfo
- }
- }
- }
コメント