本記事にはアフィリエイトリンクを含みます。Amazonのアソシエイトとして収益を得る場合があります。

Java Stream APIの書き方めも|ListとMapの変換からよく使うパターンまで

Javaのアイキャッチ Eclipse
Eclipse

StreamAPIって便利なんですが「さて、どう書くんだっけ?」ってなることありますよね。

特にListとMapを行き来する処理はパターンを覚えてしまえばあとは応用するだけなのですが、久しぶりに書くと手が止まりがちです。このメモを3歩歩いても忘れる自分のために残しておきます。

この記事でわかること

  • Collectors.toMap()を使ってListからMapへ変換する方法
  • keySet()や Stream を使ってMapのキーをListへ変換する方法
  • filter/map/flatMapなどよく使うStream処理のパターン
  • Collectorsの早見表

ListからMapへ変換する

基本の書き方

Collectors.toMap()を使います。第1引数にキー、第2引数に値を指定するだけです。

Java

具体例

Userレコードのリストをidをキー、nameを値にしたMapへ変換するパターンです。

Java

重複キーがある場合

リストに同じキーになる要素が2件以上あるとIllegalStateExceptionが発生します。3番目の引数(マージ関数)を渡すことで対処できます。

Java

注意: valueにnullが入るとNullPointerExceptionになります。nullを含む可能性があるリストはあらかじめfilterでnullを弾いておくか、HashMapを使う方法(後述)に切り替えるのが無難です。

MapのキーをListへ変換する

keySet()をそのまま使う

Java

ちなみにMap.of()はJva9から使用可能です。Java8では使えないので、あんまりスマートではないですがStreamを使って下記のような書き方もできます。

Java

Streamを使う

Streamを挟むことでソートや絞り込みと組み合わせやすくなります。

Java

補足: Map.keySet()が返すSetは順序を保証しません。順序が必要な場合はsorted()を挟むかLinkedHashMapを使うと判断できるわけですね。

よく使うStream処理のパターン

filter — 条件を絞り込む

Java

map — 要素を変換する

StreamのmapはListのmapではなく「各要素を別の値に変換する」操作です。同名なので少し紛らわしいですが、役割はまったく別物と考えるとわかりやすいです。

Java

数値に変換して合計を出したい場合はmapToInt()が便利です。

Java

flatMap — ネストしたListを平坦化する

リストのリストを1つのリストにまとめたいときに使います。

Java

distinct / sorted — 重複除去・ソート

Java

降順にしたい場合はsorted(Comparator.reverseOrder())を使います。

groupingBy — グループ化してMapに変換する

toMap()は1対1のマッピングですが、同じキーに複数の要素を紐づけたい(1対多)場合はgroupingByが向いています。

Java

joining — 文字列を結合する

Java

count / findFirst / anyMatch

Java

Collectors早見表

Collector主な用途
toList()Listに変換する。
toUnmodifiableList()変更不可のListに変換する。
toSet()Setに変換する(重複が自動で除去される)。
toMap(k, v)Mapに変換する(1対1)。
groupingBy(f)グループ化してMap<K, List<V>>に変換する(1対多)。
joining(区切り)文字列を結合する。
counting()groupingBy との組み合わせでグループ内件数を集計する。
toUnmodifiableMap(k, v)変更不可のMapに変換する。

Q&A

Q
Stream.toList()Collectors.toList()の違いは?
A

Java 16以降はstream.toList()と書けるようになりました。ただしこちらは変更不可(Unmodifiable)なListを返します。add()remove()を後から呼ぶとUnsupportedOperationExceptionになるので注意が必要です。変更が必要なListが欲しい場合はCollectors.toList()new ArrayList<>(stream.toList())で対処できます。

Q
toMap()でnullがあるとエラーになる?
A

Collectors.toMap()はvalueがnullだとNullPointerExceptionが発生します。回避策の一つはマージ関数に加えてマップファクトリを渡しHashMapを明示する方法です。

Java
Q
Streamは再利用できる?
A

一度collect()forEach()など終端操作を呼び出すとそのStreamはもう使えなくなります。再度処理したい場合はlist.stream()から作り直す必要があります。

まとめ

  • ListからMapへの変換はCollectors.toMap(keyMapper, valueMapper)が基本だよ。
  • 重複キーがあるときは第3引数のマージ関数を忘れずに渡してね。
  • MapのキーをListにするだけならnew ArrayList<>(map.keySet())が一番シンプルだよ。
  • Streamは中間操作(filter/map/sortedなど)を繋げて、終端操作(collect/count/findFirstなど)で結果を出す流れだよ。
  • groupingByは1対多のグループ化、toMapは1対1のマッピングと使い分けてね。
当ブログの内容はできる限り正確な情報を提供するよう努めていますが、利用にあたっては自己責任でお願いいたします。
掲載内容に基づく操作・設定などによって生じたトラブルや損害について、当サイトは一切の責任を負いません。
タイトルとURLをコピーしました