Java 8 の Stream API で java.util.Map をソートする方法

 Java 8 の Stream API を使っていると、タマに java.util.Map をキーもしくは値で手軽にソートしてその場で出力したくなることがあるのですが、前回どうやって書いたかすっかり忘れて、その度に API ドキュメントを漁るみたいなことを繰り返しているので、主に自分用に覚え書き。

 果たして、自分以外の需要があるのか良く分かりませんが、どなたかのお役に立ちましたら。

スポンサーリンク

読み込み中です。少々お待ち下さい

書き方

 map という Map があるとして(難しい日本語)、ソートして出力するコードを、やや冗長に書くと、例えばこんな感じ。

 キーでソート:

map.entrySet().stream() .sorted(java.util.Map.Entry.comparingByKey()) .forEach(System.out::println);

 値でソート:

map.entrySet().stream() .sorted(java.util.Map.Entry.comparingByValue()) .forEach(System.out::println);

 大文字小文字無視:

map.entrySet().stream() .sorted(java.util.Map.Entry.comparingByKey(String.CASE_INSENSITIVE_ORDER)) .forEach(System.out::println);

 降順にする:

map.entrySet().stream() .sorted(java.util.Collections.reverseOrder(java.util.Map.Entry.comparingByKey())) .forEach(System.out::println);

 パラレル化:

map.entrySet().parallelStream() .sorted(java.util.Collections.reverseOrder(java.util.Map.Entry.comparingByValue())) .forEachOrdered(System.out::println);

 以下のようにも書けますが、単純にソートするだけなら、上の書き方で十分です。

// キーでソート map.entrySet().stream() .sorted(java.util.Comparator.comparing(java.util.Map.Entry::getKey)) .forEach(System.out::println);

 ただ、場合によっては、こう書くのはアリかも知れません。

// 値でソート map.entrySet().stream() .sorted(java.util.Comparator.comparingInt(java.util.Map.Entry::getValue)) .forEach(System.out::println);

 もちろん、こんな風にも書けますが、ここでは意味無いですね。

// 値でソート map.entrySet().stream() .sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue())) .forEach(System.out::println);

サンプル

 まとめて書くと、こんな感じ。

import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Stream; import java.util.stream.Collectors; public class StreamAPIMapSortSample { public static void main(String... args) { Map<String, Integer> map = new HashMap<String, Integer>() { { put("c", 1); } { put("a", 0); } { put("b", 2); } }; // コマンドライン引数を追加 map.putAll(Stream.iterate(0, i -> ++i).limit(args.length).collect(Collectors.toMap(i -> args[i], i -> i + map.size()))); System.out.println("[キーでソート]"); map.entrySet().stream() .sorted(Entry.comparingByKey()) .forEach(System.out::println); System.out.println("[大文字小文字無視]"); map.entrySet().stream() .sorted(Entry.comparingByKey(String.CASE_INSENSITIVE_ORDER)) .forEach(System.out::println); System.out.println("[キー降順]"); map.entrySet().stream() .sorted(Collections.reverseOrder(Entry.comparingByKey())) .forEach(System.out::println); System.out.println("[値でソート]"); map.entrySet().stream() .sorted(Entry.comparingByValue()) .forEach(System.out::println); System.out.println("[パラレル化]"); map.entrySet().parallelStream() .sorted(Collections.reverseOrder(Entry.comparingByValue())) .forEachOrdered(System.out::println); } }

 実行結果。

> java StreamAPIMapSortSample X Y Z [キーでソート] X=3 Y=4 Z=5 a=0 b=2 c=1 [大文字小文字無視] a=0 b=2 c=1 X=3 Y=4 Z=5 [キー降順] c=1 b=2 a=0 Z=5 Y=4 X=3 [値でソート] a=0 c=1 b=2 X=3 Y=4 Z=5 [パラレル化] Z=5 Y=4 X=3 b=2 c=1 a=0

 ここでは特に意味が無いので使っていませんが、本格的に並列化する場合は java.util.concurrent.ConcurrentHashMap の使用を考慮しましょう(自分への戒め)。

おわりに

 正直、Java 8 の Stream API や関数インターフェース、ラムダ式を使うような案件が、いまのところ自分の趣味くらいしかほぼないので、もーホントすぐ書き方忘れちゃいます。

 記事を開いたほとんどの方にとって当たり前の内容だったかと思いますが、まぁ、冒頭に述べたように、主に自分用ということで。

この記事をシェア
  • このエントリーをはてなブックマークに追加
  • Share on Google+
  • この記事についてツイート
  • この記事を Facebook でシェア