技術関係

Kotlinのwhenのバグを生まない正しい書き方

hogeListが空の場合はnullを返そう。
hogeListが空じゃない場合はisMogeがtrueかだったらもげを返そう。
isMogeがfalseだったらisHogeがtrueかどうかを判定してtrueならほげを返そう。
両方falseならnullを返そう。

 

そんな事をwhenを使ってこう書けると思い込むと意図した結果にならない。

val hogeList: List<String> = emptyList()
val isMoge = true
val isHoge = false

val message = when (hogeList.isNotEmpty()) {
    isMoge -> {
        "もげ"
    }
    isHoge -> {
        "ほげ"
    } else -> null
}
println(message) // ほげ

// hogeListが空なのでnullが返ってほしいはずなのに ほげ が返る

 

 

原因は、というと

まずwhenの最初の引数に渡した値がブロック内の判定に使われる。
ここで言うhogeList.isNotEmpty()の値、つまりは 「true」

「hogeListが空じゃなかったら〜」という条件にはならずに「true」がブロック内での判定に使われる。

trueはisMogeと同じ値か? それともtrueはisHogeと同じ値か?ということを下記コードでは判定していることになる。

val message = when (hogeList.isNotEmpty()) { 
    isMoge -> { // ここでやっていることは true == isMoge という意図しないものに。
        "もげ"
    }
    isHoge -> { // true == isHoge はisHogeがtrue なのでこの条件に一致。結果、「ほげ」が返る。
        "ほげ"
    } else -> null
}

上記の書き方でも当然コンパイルエラーは起こらないので、うっかりバグを生み出しやすい。

 

意図した結果を生み出すにはこう修正する。

val hogeList: List<String> = emptyList()
val isMoge = true
val isHoge = false

val message = when {
    hogeList.isNotEmpty() && isMoge -> {
        "もげ"
    }
    hogeList.isNotEmpty() && isHoge -> {
        "ほげ"
    }
    else -> null
}
println(message) // もげ

hogeList.isNotEmpty()をブロック内に持ってきて&&で繋げる。

条件が複数になると冗長に見えてしまうが他に書きようがないっぽい。

ともあれこれで

hogeListが空の場合はnullを返す。空じゃない場合はisMogeisHogeを判定する。
判定した結果どちらも当てはまらない場合はnullを返す。

というロジックを正しく書ける。

スポンサーリンク

環境

Kotlin v1.5.21

参考

https://kotlinlang.org/docs/control-flow.html

コメント

タイトルとURLをコピーしました