LoginSignup
11
1

More than 3 years have passed since last update.

【Kotlin】Collectionの要素を安全に取り出す

Last updated at Posted at 2019-11-30

この記事はMicroAd Advent Calendar 2019の1日目の記事です。

状況

ListSetと言ったCollectionから要素を1つ取り出す」場合、getメソッドやfirst関数を使いたくなります。

val list: List<String> = listOf("a", "b", "c")

val first: String? = list.first { it == "d" }
val secondElement: String? = list.get(1) // 実際は[]を用いることができるが、説明のためgetを用いる

しかし、これらの処理は、該当する要素が見つからなかった(e.g. emptyだった、検索条件に引っかからなかった、要素以上のインデックスだった、等)場合、それぞれNoSuchElementExceptionIndexOutOfBoundsExceptionを投げます。
つまり、「見つからなかったらnullにする(or した上でnullだった時の処理を入れる)」的な処理に使うことはできません。

サンプルコードの通り、これらの取得結果をnullable型に代入しても警告やエラーにならないため、深いバグになりやすい点でも注意が必要です。

対処

(条件分岐や例外処理をしない形での)Collectionの要素を安全な取り出しは、nullやデフォルト値を返す関数を用いることで実現できます。
ここでは具体的に以下の3種類を紹介します。

  • ~OrElse
  • ~OrNull
  • find

~系」としてまとめていますが、これらは関数によって有ったりなかったりします。
その具体的な有無に関してはソースコードをご覧下さい。

~OrElse系関数を用いる

見つからなければデフォルト値を返すのが~OrElse系関数です。
getOrElseelementAtOrElse系が有ります。

この~OrNull系関数は、以下のように、デフォルトの値生成にInt -> デフォルト値のラムダを取ります。

val index // 取得対象インデックス想定

list.getOrElse(index) { i -> // iにはindexが入ってくる
    // デフォルト値の生成処理
}

~OrNull系関数を用いる

見つからなければnullを返すのが~OrNull系関数です。
firstOrNullgetOrNullなどが有ります。

find系関数を用いる

~OrNull系関数と同じく、見つからなければnullを返すのがfind系関数です。
findfindLast関数が有ります。

内容的にはそれぞれfirstOrNulllastOrNullを呼び出しています。

終わりに

この記事では条件分岐や例外処理をしない形でCollectionの要素を安全に取り出す方法についてまとめました。

この記事を書いたきっかけは、チームの人間が何人も「JavaStream APIfindFirstメソッドとfirst関数の挙動が違う」という罠を踏んだことです。
しかも前述の通りnullable型に代入しても警告やエラーにならないため、ヒヤッとする所に取り残してしまうことも有りました。

get系はともかく、何か検索して取ってくるような処理では「見つからなければnullまたはデフォルト値」を返すだけでいい気がするんですが、何でそうなっていないんでしょうか……。

ともあれ、この記事がCollectionの要素を安全に取り出すことに役立てば幸いです。

11
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
1