白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

Comparatorの型推論

こんばんは。

雪、降りましたね。
寒い…。


さて、Streamなお話。

Streamを処理する際、ソートには中間メソッドのsortedを使います。
このメソッドの引数はComparatorですが、自然順序付けを使わないような場合には、
comparingやcomparingIntなどのメソッドを使って作ることが多いです。

Stream<String> stream = Stream.of("いち", "に", "さん", "し", "ご");

stream.sorted(Comparator.comparing(s -> s.length()))
      .forEach(System.out::println);

こんな感じです。

結果はこうなります。

に
し
ご
いち
さん

はい。

で、逆順にしたいときもありますが、
そんな場合にはreverseメソッドを使います。

stream.sorted(Comparator.comparing(s -> s.length()).reversed())
      .forEach(System.out::println);

こんな感じです。
が、これはs.length()のところで型が拾えずにエラーになってしまいます。
おや?

stream.sorted(Comparator.comparing((String s) -> s.length()).reversed())
      .forEach(System.out::println);

仕方がないのでラムダにヒントをあげるとちゃんと動きました。

stream.sorted(Comparator.<String, Integer>comparing(s -> s.length()).reversed())
      .forEach(System.out::println);

ジェネリクスを付けてあげてもOKです。

stream.sorted(Comparator.comparing(String::length).reversed())
      .forEach(System.out::println);

メソッド参照にするとがんばれるようです。

stream.sorted(Comparator.comparing(s -> s.length(), Comparator.reverseOrder()))
      .forEach(System.out::println);

reverseOrderを後からくっつけても大丈夫なようです。


・・・えーと?
要するにコンパイラが二段階の型推論をがんばれないってことですかね。

class Test<T> {
    static <S> Test<S> get() {
        return new Test<>();
    }
    Test<T> method() {
        return this;
    }
}

こんな感じにクラスを作ると、

Test<String> t1 = Test.get();

はOKだけど、

Test<String> t2 = Test.get().method();

はNGです。


まぁ、しょうがないのかもしれないですが、直感的ではないですよね。
むむ。