web-dev-qa-db-ja.com

Comparator.reversed()はラムダを使用してコンパイルしません

私はいくつかのユーザーオブジェクトのリストを持っていますが、リストを並べ替えようとしていますが、メソッドリファレンスを使用してのみ動作し、ラムダ式ではコンパイラがエラーを返します:

List<User> userList = Arrays.asList(u1, u2, u3);
userList.sort(Comparator.comparing(u -> u.getName())); // works
userList.sort(Comparator.comparing(User::getName).reversed()); // works
userList.sort(Comparator.comparing(u -> u.getName()).reversed()); // Compiler error

エラー:

com\Java8\collectionapi\CollectionTest.Java:35: error: cannot find symbol
            userList.sort(Comparator.comparing(u -> u.getName()).reversed());
                                                     ^
symbol:   method getName()
location: variable u of type Object
1 error
98
Andrey

これは、コンパイラの型推論メカニズムの弱点です。ラムダのuのタイプを推測するには、ラムダのターゲットタイプを確立する必要があります。これは次のように達成されます。 userList.sort()は、タイプ_Comparator<User>_の引数を予期しています。最初の行では、Comparator.comparing()は_Comparator<User>_を返す必要があります。これは、Comparator.comparing()Function引数を取るUserを必要とすることを意味します。したがって、最初の行のラムダでは、uUser型でなければならず、すべてが機能します。

2行目と3行目では、reversed()への呼び出しが存在するため、ターゲットの入力が中断されます。理由はよくわかりません。 reversed()のレシーバーと戻り値のタイプは両方とも_Comparator<T>_であるため、ターゲットタイプをレシーバーに戻す必要がありますが、そうではありません。 (私が言ったように、それは弱点です。)

2行目のメソッドリファレンスは、このギャップを埋める追加の型情報を提供します。この情報は3行目にないため、コンパイラはuObject(最後の手段の推論フォールバック)であると推測し、失敗します。

メソッド参照を使用できる場合は、明らかにそれを行うと動作します。追加のパラメーターを渡す場合など、メソッド参照を使用できない場合があるため、ラムダ式を使用する必要があります。その場合は、ラムダで明示的なパラメータータイプを指定します。

_userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());
_

将来のリリースでこのケースに対応するために、コンパイラーを拡張する可能性があります。

121
Stuart Marks

2つの引数_Comparator.comparing_を2番目の引数としてComparator.reverseOrder()とともに使用することにより、この制限を回避できます。

_users.sort(comparing(User::getName, reverseOrder()));
_
78
Misha