Stream API を使用して Map をソートする

# 概要

Java にて Map に格納されている Entry を Value (降順) 、Key (昇順) の順番でソートしたいと考えました。
簡単にソートしたいので、Stream API を使用することを考えましたが、使用方法について少しはまってしまったので自分用に備忘録を残したいと思います。

ソート前

| key | value|
|-------:|-------:|
|21|10|
|11|12|
|2|10|

ソート後

| key | value|
|-------:|-------:|
|11|12|
|2|10|
|21|10|

# 実装

```Sort.java

import java.util.*;
import java.util.stream.Collectors;

public class Sort {

    public static void main(String[] args) {
        // 挿入順は担保されないが上記図のイメージに合わせて挿入
        Map<Integer, Integer> map = new HashMap<>();
        map.put(21, 10);
        map.put(11, 12);
        map.put(2, 10);
        Map<Integer, Integer> result = map.entrySet().stream()
                .sorted(Map.Entry.<Integer, Integer>comparingByValue().reversed()
                        .thenComparing(Map.Entry.comparingByKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

        for (Map.Entry<Integer, Integer> sorted : result.entrySet()) {
            System.out.printf("Key is %d  value is %d \n", sorted.getKey(), sorted.getValue());
        }
    }
}

```

```text:結果
Key is 11  value is 12 
Key is 2  value is 10 
Key is 21  value is 10 
```

## 補足

[HashMap](https://docs.oracle.com/javase/jp/8/docs/api/java/util/HashMap.html) では挿入順序が担保されないので、[LinkedHashMap](https://docs.oracle.com/javase/jp/8/docs/api/java/util/LinkedHashMap.html) を使用しています。

> HashMap
>Mapインタフェースのハッシュ表に基づく実装です。この実装は、マップに関連するオプションのオペレーションをすべてサポートし、null値およびnullキーを使用できます。HashMapクラスはHashtableと同じとみなしてもかまいませんが、HashMapの方は同期がとられず、nullの場合もあります。このクラスはマップの順序を保証しません。特に、その順序を常に一定に保つことを保証しません。

>LinkedHashMap
>この実装では、HashMapおよびHashtableで提供される未指定(無秩序)の順序がクライアントで起きることはありません(TreeMapのように負荷が増えることもありません)。この実装を使用することで、元のマップの実装にかかわらず、元のマップと同じ順序のコピーを作成できます。


# 参考

[こちらのページ](http://www.java67.com/2017/07/how-to-sort-map-by-values-in-java-8.html) から学習させていただきました。

[toMap](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-) の引数は、下記となっています。

|N| 引数名| 内容|
|-------:|-------|-------|
|1| keyMapper| 新規Map のため Key を生成するための関数 |
|2| valueMapper| 新規Map のため value を生成するための関数 |
|3| mergeFunction| 新規キー (例では key になる)|
|4| mapSupplier| 新規Mapインスタンスを生成する関数|

```Collectors.java

    * @param <T> the type of the input elements
     * @param <K> the output type of the key mapping function
     * @param <U> the output type of the value mapping function
     * @param <M> the type of the resulting {@code Map}
     * @param keyMapper a mapping function to produce keys
     * @param valueMapper a mapping function to produce values
     * @param mergeFunction a merge function, used to resolve collisions between
     *                      values associated with the same key, as supplied
     *                      to {@link Map#merge(Object, Object, BiFunction)}
     * @param mapSupplier a function which returns a new, empty {@code Map} into
     *                    which the results will be inserted
     * @return a {@code Collector} which collects elements into a {@code Map}
     * whose keys are the result of applying a key mapping function to the input
     * elements, and whose values are the result of applying a value mapping
     * function to all input elements equal to the key and combining them
     * using the merge function
     *
     * @see #toMap(Function, Function)
     * @see #toMap(Function, Function, BinaryOperator)
     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
     */
    public static <T, K, U, M extends Map<K, U>>
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) {

}
```