
Map へ変換(キー重複無し)
以下の Item
のリストを id をキーにした Map に変換します。
List<Item> list = Arrays.asList( new Item(9, "apple"), new Item(3, "lemon"), new Item(6, "peach"));
collect()
に Collectors.toMap
を指定した終端処理で Map に変換することができます。
list.stream().collect(
Collectors.toMap(Item::getId, e -> e));
// {3 = Item{3, 'lemon'}, 6 = Item{6, 'peach'}, 9 = Item{9, 'apple'}}
上記は UnaryOperator.identity()
を使って以下のように書いても同じです。
list.stream().collect( Collectors.toMap(Item::getId, UnaryOperator.identity()));
UnaryOperator
は単項演算用の関数インターフェースで、identity()
は引数をそのまま返す定義となっています。
public interface UnaryOperator<T> extends Function<T, T> { static <T> UnaryOperator<T> identity() { return t -> t; } }
Item の中身を展開する場合は以下のようにすることができます。
list.stream().collect( Collectors.toMap(Item::getId, Item::getName))); // {3 = lemon, 6 = peach, 9 = apple}
Map へ変換(キー重複有り)
キーが重複する場合は注意が必要です。
以下の例では、id の 6
が重複します。
List<Item> list = Arrays.asList( new Item(9, "apple"), new Item(3, "lemon"), new Item(6, "peach"), new Item(6, "banana")); // duplicate
toMap()
の第三引数を指定しない場合は、キー重複時に java.lang.IllegalStateException: Duplicate key Item{6, 'peach'}
の例外がスローされます。
list.stream().collect(
Collectors.toMap(Item::getId, e -> e));
// java.lang.IllegalStateException: Duplicate key Item{6, 'peach'}
キー重複する場合は、重複時にどちらを採用するかを、toMap()
の第三引数で指定する必要があります。
以下は先勝ちとする例です。
list.stream().collect(
Collectors.toMap(Item::getId, e -> e, (e1, e2) -> e1));
// {3=Item{3, 'lemon'}, 6=Item{6, 'peach'}, 9=Item{9, 'apple'}}
LinkedHashMap へ変換
並びを維持したい場合は、第四引数の mapSupplier に LinkedHashMap::new
を指定します。
list.stream().collect( Collectors.toMap(Item::getId, e -> e, (e1, e2) -> e1, LinkedHashMap::new))); // {9 = Item{9, 'apple'}, 3 = Item{3, 'lemon'}, 6 = Item{6, 'peach'}}
任意キーでグルーピング
特定の条件でグルーピングする場合は Collectors.groupingBy
を使います。
Map<Integer, List<Item>> m = list.stream().collect( Collectors.groupingBy(Item::getId)); // {3 = [Item{3, 'lemon'}], // 6 = [Item{6, 'peach'}, Item{6, 'banana'}], // 9 = [Item{9, 'apple'}]}
id が同じものをグルーピングできました。
グルーピングして集計
売上日別の価格集計などは Collectors.reducing
で畳み込みを行います。
Map<LocalDate, BigDecimal> m = list.stream().collect(
Collectors.groupingBy(
Item::getSalesDate,
Collectors.reducing(BigDecimal.ZERO, Item::getPrice, BigDecimal::add)));
groupingBy()
の第二引数に Collectors.reducing
を指定して集計しています。
グループ分け
Collectors.partitioningBy
はある条件で2つのグループに分ける場合に利用します。
Map<Boolean, List<Item>> m = list.stream().collect( Collectors.partitioningBy(item -> item.getId() % 2 == 0)); // {false=[Item{id=9, name='apple'}, Item{id=3, name='lemon'}], // true=[Item{id=6, name='peach'}, Item{id=6, name='banana'}]}
id が奇数か偶数かにより分類する例です。

Javaによる関数型プログラミング ―Java 8ラムダ式とStream
- 作者:Venkat Subramaniam
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/10/24
- メディア: 単行本(ソフトカバー)

- 作者:Joshua Bloch
- 出版社/メーカー: Addison-Wesley Professional
- 発売日: 2018/01/06
- メディア: ペーパーバック

Modern Java in Action: Lambdas, streams, functional and reactive programming
- 作者:Raoul-Gabriel Urma,Mario Fusco,Alan Mycroft
- 出版社/メーカー: Manning Publications
- 発売日: 2018/11/20
- メディア: ペーパーバック