概要
【Java】ListをStreamで処理する方法 7選!
【Java】SetをStreamで処理する方法 7選!
に続き、Map編です。
Mapをstreamで扱う場合、entrySetまたはKeySetでSetビューを返してかstreamを呼ぶ必要があります。
また、HashSetと同様にHashMapは順序が保証されていないため、最初から順序を保証しておきたい場合はLinkedHashMapを使う必要があります。
実装例は、Setの時と同様によく使うであろうHashMapで解説していきます。
実装例
特定の要素のみを取得する
中間処理:カテゴリーが”玩具”だけのProductに絞り込みます。
終端処理:HashMapに変換して結果を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Test void Map_特定の要素のみを取得する() { Map<Integer, Product> products = new HashMap<>() { { put(1, new Product("衣類", "靴下", 200)); put(2, new Product("食品", "ふりかけ", 100)); put(3, new Product("玩具", "プラモデル", 1000)); } }; HashMap<Integer, Product> toys = products.entrySet().stream() .filter(product -> "玩具".equals(product.getValue().category())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, HashMap::new)); assertThat(toys.get(3).name(), is("プラモデル")); } |
合計を算出する
中間処理:IntStreamに変換します。
終端処理:合計した結果を返します
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@Test void Map_合計を算出する() { Map<Integer, Product> products = new HashMap<>() { { put(1, new Product("衣類", "靴下", 200)); put(2, new Product("食品", "ふりかけ", 100)); put(3, new Product("玩具", "プラモデル", 1000)); } }; int sumAmount = products.entrySet().stream() .mapToInt(product -> product.getValue().price()) .sum(); assertThat(sumAmount, is(1300)); } |
並べ替えた結果を取得する(昇順)
中間処理:金額の昇順で並び替える。(テスト用に最初の1件だけ取得)
終端処理:LinkedHashMapに変換して結果を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Test void Map_並べ替えた結果を取得する_昇順() { Map<Integer, Product> products = new HashMap<>() { { put(1, new Product("衣類", "靴下", 200)); put(2, new Product("食品", "ふりかけ", 100)); put(3, new Product("玩具", "プラモデル", 1000)); } }; // テストのために、並び変えた結果の最初の1要素をlimitで取得 LinkedHashMap<Integer, Product> ascOrderOfPrice = products.entrySet().stream() .sorted(Map.Entry.comparingByValue( Comparator.comparing(Product::price))) .limit(1) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); // 最も金額の小さい「"食品", "ふりかけ」が取得できている assertThat(ascOrderOfPrice.containsKey(2), is(true)); } |
並べ替えた結果を取得する(降順)
中間処理:金額の降順で並び替える。(テスト用に最初の1件だけ取得)
終端処理:LinkedHashMapに変換して結果を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Test void Map_並べ替えた結果を取得する_降順() { Map<Integer, Product> products = new HashMap<>() { { put(1, new Product("衣類", "靴下", 200)); put(2, new Product("食品", "ふりかけ", 100)); put(3, new Product("玩具", "プラモデル", 1000)); } }; // テストのために、並び変えた結果の最初の1要素をlimitで取得 LinkedHashMap<Integer, Product> descOrderOfPrice = products.entrySet().stream() .sorted(Map.Entry.comparingByValue( Comparator.comparing(Product::price).reversed())) .limit(1) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); // 最も金額の大きい「"玩具", "プラモデル"」が取得できている assertThat(descOrderOfPrice.containsKey(3), is(true)); } |
最初の要素を取得する
中間処理:Keyの昇順で並び替える。
終端処理:最初の1件を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Test void Map_最初の要素を取得する() { Map<Integer, Product> products = new HashMap<>() { { put(1, new Product("衣類", "靴下", 200)); put(2, new Product("食品", "ふりかけ", 100)); put(3, new Product("玩具", "プラモデル", 1000)); } }; Entry<Integer, Product> firstOfAscPrice = products.entrySet().stream() .sorted(Map.Entry.<Integer, Product>comparingByKey()) .findFirst() .orElse(null); assertThat(firstOfAscPrice.getValue().name(), is("靴下")); } |
最後の要素を取得する
中間処理:Keyの降順で並び替える。
終端処理:最初の1件を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Test void Map_最後の要素を取得する() { Map<Integer, Product> products = new HashMap<>() { { put(1, new Product("衣類", "靴下", 200)); put(2, new Product("食品", "ふりかけ", 100)); put(3, new Product("玩具", "プラモデル", 1000)); } }; Entry<Integer, Product> firstOfDescPrice = products.entrySet().stream() .sorted(Map.Entry.<Integer, Product>comparingByKey().reversed()) .findFirst() .orElse(null); assertThat(firstOfDescPrice.getValue().name(), is("プラモデル")); } |
中間処理:Formatterで変換した文字列を生成する。
終端処理:Listに変換した結果を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@Test void Map_なんらかの値に変換した値を取得する() { Map<Integer, Product> products = new HashMap<>() { { put(1, new Product("衣類", "靴下", 200)); put(2, new Product("食品", "ふりかけ", 100)); put(3, new Product("玩具", "プラモデル", 1000)); } }; List<String> formatedList = products.entrySet().stream() .map(entry -> new Formatter().format("[key: %d, value: %s, %s, %d]", entry.getKey(), entry.getValue().category(), entry.getValue().name(), entry.getValue().price()) .toString()) .collect(Collectors.toList()); // HashMapは順序が保証されていないので、玩具を含んだ文字列のみを抽出してテストする assertThat(formatedList.stream() .filter(str -> str.toString().contains("玩具")) .findFirst() .orElse(null), is("[key: 3, value: 玩具, プラモデル, 1000]")); } |
まとめ
- MapはentrySetまたはkeySetでSetビューを返してからStreamメソッドを呼び出す。
- HashMapもHashSetと同様に順序が保証されていないので、最初から順序を保証する必要がある場合はLinkedHashMapを使用する。
最後に
独学が難しい、エラーの解消に時間がかかる、今学ぶべき技術は何だろうといった悩みがあるようだったら現役エンジニアによるオンラインのサポートサービスを検討してみて下さい。
回答率100%の掲示板に質問し放題のオンラインサービス