Kotlin Advent Calendar 2021の7->11日目の記事です
概要
safe call(?.)とelvis(?:)でNullableを上手く処理するパターン
Kotlin初心者が引っかかりやすいのでメモしておく
前提
スコープ関数 let
対象に引数の無名関数を適用する
99.let { it.toString().first() } // => "9"
演算子 safe call ?.
対象がnot nullであれば右辺のメソッドを呼び出し、nullであれば何もせずnullを返す
イメージ
if (target != null) {
target.method()
} else {
null
}
REPL
var target: Int? = 99
target?.toString() // => "99"
target = null
target?.toString() // => null
演算子 elvis ?:
対象がnot nullであればその値をそのまま返し、nullであれば右辺を返す
Nullableにデフォルト値を設定するようなイメージ
イメージ
if (target != null) {
target
} else {
right
}
REPL
var target: String? = "dummy"
target ?: "target is null" // => "dummy"
target = null
target ?: "target is null" // => "target is null"
実際の適用例
以下のような処理を想定する
enum class Level(val code: Int) {
HIGH(1),
LOW(2),
NONE(0)
}
val result =
if (target != null) {
if (target > 15) {
Level.HIGH
} else {
Level.LOW
}
} else {
Level.NONE
}
}
この処理に let
?.
?:
を適用すると一行で書ける
val result = target?.let { if (it > 15) Level.HIGH else Level.LOW } ?: Level.NONE
1段階ずつ演算子の処理を追うと以下のようになる
val target: Int? = 99
target?.let { if (it > 15) Level.HIGH else Level.LOW } ?: Level.NONE
// => 99?.let { if (it > 15) Level.HIGH else Level.LOW } ?: Level.NONE
// => 99.let { if (it > 15) Level.HIGH else Level.LOW } ?: Level.NONE
// => (if (99 > 15) Level.HIGH else Level.LOW) ?: Level.NONE
// => Level.HIGH ?: Level.NONE
// => Level.HIGH
val target: Int? = null
target?.let { if (it > 15) Level.HIGH else Level.LOW } ?: Level.NONE
// => null?.let { if (it > 15) Level.HIGH else Level.LOW } ?: Level.NONE
// => null ?: Level.NONE
// => Level.NONE
感想
初見だと抽象的で認知的な負荷が高いが、慣れるとJavaのnullを簡潔で柔軟に処理できる優れた設計であることが分かる