【Java】IntStreamで要素を逆順にソートする

# はじめに

[こちらの記事](https://qiita.com/nkojima/items/dc1775049715bcfbd29e)にも書いている、IntStream.range()とIntStream.rangeClosed()は、指定した範囲の連続する値を得る際に非常に便利です。

しかし、これらのメソッドで得られたIntStreamは、sortedメソッドだけでは逆順にできません。

例えば以下のコードの場合、sortedメソッドの引数にComparator.reverseOrder()をとることが出来ないため、コンパイルエラーとなってしまいます。
※[IntStreamクラスのsortedメソッド](https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/IntStream.html#sorted--)は、引数を持たないメソッドとして定義されています。

```java:
    static void reverse() {
        IntStream.rangeClosed(1, 10)                        // IntStreamの生成
            .sorted(Comparator.reverseOrder())              // 中間操作
            .forEach(num -> System.out.println(num));       // 終端処理
    }
```

# 解決策1：boxedメソッドの利用

中間処理としてboxedメソッドを入れて、IntStreamをStream&lt;Integer&gt;に変換することで、sortedメソッドだけで簡単に逆順にすることができました。

※[Streamクラスのsortedメソッド](https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html#sorted-java.util.Comparator-)は、Comparatorを引数にとることができます。

```java:
    static void reverse() {
        IntStream.rangeClosed(1, 10)                        // IntStreamの生成
            .boxed()                                        // ★追加した中間操作（IntStream->Stream<Integer>）
            .sorted(Comparator.reverseOrder())              // 中間操作
            .forEach(num -> System.out.println(num));       // 終端処理
    }
```

# 解決策2：IntStreamの使用を諦める

IntStreamを使わずにStream（Stream&lt;Integer&gt;）を使えば、この問題を回避することができます。

その代わり、IntStream.range()とやIntStream.rangeClosed()などは使えなくなってしまいます...

```java:
    static void reverse2() {
        Integer[] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        Stream<Integer> stream = Arrays.stream(values);
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        Arrays.stream(values)                                // streamの生成
            .sorted(Comparator.reverseOrder())               // 中間操作
            .forEach(num -> System.out.println(num));        // 終端処理
    }

    /**
     * @k73i55no5さんによる改善版。listを介さずに直接配列からstreamに変換している。
     */
    static void reverse3() {
        Integer[] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        
        Arrays.stream(values)                               // streamの生成
            .sorted(Comparator.reverseOrder())              // 中間操作
            .forEach(num -> System.out.println(num));       // 終端処理
    }
```

# 解決策3：符号を変換してからソートする

@swordoneさんからコメントで教えて頂いた方法で、「プラスマイナスの符号を変換して並べ替えた後、再び符号を元に戻す」というものです。

こちらでは未確認ですが、この方法を使うには幾つかの制約があるようです。
コメントでは「ネタ」と言われていますが、全く想定していない方向からボールが飛んできたように感じるほど驚きました。

```java:
    static void reverse4() {
        IntStream.rangeClosed(1, 10)                         // streamの生成
            .map(i -> -i)                                    // 中間操作（正の数->負の数）
            .sorted()                                        // 中間操作
            .map(i -> -i)                                    // 中間操作（負の数->正の数）
            .forEach(num -> System.out.println(num));        // 終端処理
    }
```

# まとめ

* 「IntStreamをStream&lt;Integer&gt;に変換する」という方法で解決できるとは思いませんでした。
 * そもそも、IntStreamとStream&lt;Integer&gt;の違いを全く理解していなかったです...
* 解決策2は単なる逃げですが、絶対にIntStreamを使わなければダメということでなければ、これで良いのかもしれません。
* Java8のStream APIは苦手（というより使う機会がない）なので、少しでも触れる機会を増やしていきたいです。
 * @LouiS0616さんのコメント（※mapメソッドを使う方法）については、もう少し勉強してから追記したいと思います。