Help us understand the problem. What is going on with this article?

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

この記事は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の要素を安全に取り出すことに役立てば幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした