1. ホーム
  2. java

[解決済み] Comparator.reversed()がラムダを使用してコンパイルされない

2022-07-04 14:38:35

質問

Userオブジェクトを含むリストがあり、そのリストをソートしようとしていますが、メソッド参照を使用してのみ動作し、ラムダ式ではコンパイラがエラーを出します。

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

どのように解決するのですか?

これは、コンパイラの型推論機構の弱点です。の型を推論するために u をラムダ内で推論するために ターゲット型 を設定する必要があります。これは以下のように実現される。 userList.sort() が期待する引数は Comparator<User> . 最初の行では Comparator.comparing() を返す必要があります。 Comparator<User> . このことは Comparator.comparing() が必要であることを意味します。 Function を取るもので User の引数を取る。したがって、1行目のラムダでは u は必ず User であり、すべてが動作します。

2行目と3行目では、ターゲットのタイピングは reversed() . のレシーバとリターンタイプの両方が存在するためです。 reversed()Comparator<T> であるため、ターゲットの型がレシーバーに伝搬されるように思えるのですが、そうではありません。(言ったように、それは弱点です)。

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

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

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

将来のリリースでは、このケースをカバーするためにコンパイラを拡張することが可能かもしれません。