当サイトは、アフィリエイト広告を利用しています

【java8】Collectors.toMapの使い方

作成日:2022月03月15日
更新日:2023年12月14日

java8のStreamAPIのtoMap(終端処理)を使って
Mapへの変換処理を行う方法をまとめる。

streamAPI については下記の本が詳しく書いてありおススメです!

また当ブログで紹介しているjava8のstreamAPIを使った
コレクションや配列の操作方法を
下記記事でメソッド別にまとめています!

toMap(終端処理)とは?

forEachなどと同じStream内で加工された値を最終的に出力するcollectorの一つ。
toMapなのでMapオブジェクトの形に加工して出力する

基本構文

引数の数で3パターンの使い方が可能。
引数はすべて関数型インターフェースで指定する。

引数が二つの場合

引数には下記を指定する

  • 第一引数はMapのkey
  • 第二引数はMapのvalue

両方とも一つの値を受け取って一つの値を返す関数型インターフェースのFunction型の
関数を指定する

java
// 構文
.collect(Collectors.toMap(Function<T,R>,Function<T,R>))
// 使用時のイメージ
.collect(Collectors.toMap(e->e.getId(),e->getName()))
// メソッド参照ver
.collect(Collectors.toMap(Item::getId,Item::getName))

引数が三つの場合

引数には下記を指定する

  • 第一引数はMapのkey
  • 第二引数はMapのvalue
  • 第三引数はkey重複時に先勝ちか後勝ちか

第一引数と第二引数は引数が二つの場合と同じ。
第三引数には二つの引数で一つの値を返す関数型インターフェースのBinaryOperator型の関数を指定する

java
// 構文
.collect(Collectors.toMap(Function<T,R>,Function<T,R>,BinaryOperator<T>))
// 使用時のイメージ
.collect(Collectors.toMap(e->e.getId(),e->e.getName(),(oldVal,newVal) -> newVal))

引数が4つの場合

引数には下記を指定する

  • 第一引数はMapのkey
  • 第二引数はMapのvalue
  • 第三引数はkey重複時に先勝ちか後勝ちか
  • 第四引数はMapインタフェースを実装したクラス※最終的に取得するMapを指定

第一引数~第三引数は引数は同じ。
第四引数には最終的に出力したいMapクラスを指定する。

java
// 構文
.collect(Collectors.toMap(Function<T,R>,Function<T,R>,BinaryOperator<T>,Supplier<M> mapSupplier))
// 使用時のイメージ
.collect(Collectors.toMap(e->e.getId(),e->getName(),(oldVal,newVal) -> newVal,()->new LinkedHashMap<>()))
// メソッド参照
.collect(Collectors.toMap(Item::getId,Item::getName,(oldVal,newVal) -> newVal,LinkedHashMap::new))

実装してみる

実際にいくつかサンプルを実装してみる

オブジェクトListをMap変換する~パターン1~

PresonオブジェクトのListをnameをkeyにして
valueにPresonオブジェクト入れたLinkedHashMapを作成してみる key重複の場合は後勝ちにする。

java
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
class Person {
private final String name;
private final int weight;
Person(String name, int weight) {
this.name = name;
this.weight = weight;
}
public String getName() {
return this.name;
}
public int getWeight() {
return this.weight;
}
}
List<Person> personList = Arrays.asList(
new Person("太郎", 72),
new Person("二郎", 79),
new Person("二郎", 99)
);
// オブジェクトリストをMapに変換する
LinkedHashMap<String,Person>personMap =
personList.stream().collect(
Collectors.toMap(Person::getName, e -> e,(e1,e2)->e2,LinkedHashMap::new));
// 変換したMapの中身をループで出力する
personMap.entrySet().stream().forEach(map->{
System.out.println(map.getKey()+"のインスタンス");
System.out.println("Mapのkey : " + map.getKey());
System.out.println("Mapのvalue(name) : " + map.getValue().getName());
System.out.println("Mapのvalue(weight)" + map.getValue().getWeight());
});
}
}
// 実行結果
// 太郎のインスタンス
// Mapのkey : 太郎
// Mapのvalue(name) : 太郎
// Mapのvalue(weight)72
// 二郎のインスタンス
// Mapのkey : 二郎
// Mapのvalue(name) : 二郎
// Mapのvalue(weight)99

オブジェクトListをMap変換する~パターン2~

PresonオブジェクトのListをnameをkeyにして
valueにPresonオブジェクトのweight入れたLinkedHashMapを作成してみる key重複の場合は先勝ちにする。

java
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
class Person {
private final String name;
private final int weight;
Person(String name, int weight) {
this.name = name;
this.weight = weight;
}
public String getName() {
return this.name;
}
public int getWeight() {
return this.weight;
}
}
List<Person> personList = Arrays.asList(
new Person("太郎", 72),
new Person("二郎", 79),
new Person("二郎", 99)
);
// オブジェクトリストをMapに変換する
LinkedHashMap<String,Integer>personMap =
personList.stream().collect(
Collectors.toMap(Person::getName,Person::getWeight ,(e1,e2)->e1,LinkedHashMap::new));
// 変換したMapの中身をループで出力する
personMap.entrySet().stream().forEach(map->{
System.out.println(map.getKey()+"のエントリー");
System.out.println("Mapのkey : " + map.getKey());
System.out.println("Mapのvalue : " + map.getValue());
});
}
}
// 太郎のエントリー
// Mapのkey : 太郎
// Mapのvalue : 72
// 二郎のエントリー
// Mapのkey : 二郎
// Mapのvalue : 79

注意点

下記のようにtoMapを使う時にvalueの値がnullとなる場合はNullPointerExceptionが発生する。

java
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
class Person {
private String name;
private String weight;
Person(String name, String weight) {
this.name = name;
this.weight = weight;
}
public String getName() {
return this.name;
}
public String getWeight() {
return this.weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
}
List<Person> personList = Arrays.asList(
// nullをセット
new Person("太郎", null),
new Person("二郎", "79"),
new Person("二郎", "99")
);
// オブジェクトリストをMapに変換する
LinkedHashMap<String,String>personMap =
personList.stream().collect(
Collectors.toMap(Person::getName,Person::getWeight ,(e1,e2)->e1,LinkedHashMap::new));
// 変換したMapの中身をループで出力する
personMap.entrySet().stream().forEach(map->{
System.out.println(map.getKey()+"のエントリー");
System.out.println("Mapのkey : " + map.getKey());
System.out.println("Mapのvalue : " + map.getValue());
});
}
}

対応方法

toMapメソッドは使えないのでcollectメソッドで直接作る。

java
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
class Person {
private String name;
private String weight;
Person(String name, String weight) {
this.name = name;
this.weight = weight;
}
public String getName() {
return this.name;
}
public String getWeight() {
return this.weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
}
List<Person> personList = Arrays.asList(
new Person("太郎", null),
new Person("二郎", "79"),
new Person("二郎", "99")
);
// オブジェクトリストをMapに変換する
Map<String,String>personMap =
personList.stream().collect(
// 中間コンテナを生成
// 最初の1回だけ実行
()->new HashMap<>(),
// 中間コンテナに値をセットしていく
// stermの要素の数だけ実行される
(Map m,Person p)->m.put(p.getName(),p.getWeight()),
// 中間コンテナからの結果をマージする
// 順次ストリームの場合実行されない
(m,m2)->m.putAll(m2)
);
// 変換したMapの中身をループで出力する
personMap.entrySet().stream().forEach(map->{
System.out.println(map.getKey()+"のエントリー");
System.out.println("Mapのkey : " + map.getKey());
System.out.println("Mapのvalue : " + map.getValue());
});
}
}
// 二郎のエントリー
// Mapのkey : 二郎
// Mapのvalue : 99
// 太郎のエントリー
// Mapのkey : 太郎
// Mapのvalue : null

collectの中身をメソッド参照で書いた場合

メソッド参照で書くと下記のような感じになる。

java
// オブジェクトリストをMapに変換する
Map<String,String>personMap =
personList.stream().collect(
// 中間コンテナを生成
// 最初の1回だけ実行
HashMap::new,
// 中間コンテナに値をセットしていく
// stermの要素の数だけ実行される
(Map m,Person p)->m.put(p.getName(),p.getWeight()),
// 中間コンテナからの結果をマージする
// 順次ストリームの場合実行されない
Map::putAll
);

参考

Java Stream でよく使う Map 変換
Java8のCollectors.toMap()の使い方
Streamのcollectメソッドを学ぶ

新着記事

タグ別一覧
top