Лямбда-выражение и универсальный метод



Предположим, у меня есть универсальный интерфейс:



interface MyComparable<T extends Comparable<T>>  {
public int compare(T obj1, T obj2);
}


и метод sort:



public static <T extends Comparable<T>> 
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}


я могу вызвать этот метод и передаем лямбда-выражение в качестве аргумента:



List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));


это будет работать нормально.



но теперь, если я сделаю интерфейс не универсальным, а метод generic:



interface MyComparable {
public <T extends Comparable<T>> int compare(T obj1, T obj2);
}

public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable comp) {
}


а затем вызвать это как:



List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));


он не компилируется. Он показывает ошибку в лямбда-выражении говоря:




"целевой метод является универсальным"




ОК, когда я скомпилировал его с помощью javac, он показывает следующие ошибки:



SO.java:20: error: incompatible types: cannot infer type-variable(s) T#1
sort(list, (a, b) -> a.compareTo(b));
^
(argument mismatch; invalid functional descriptor for lambda expression
method <T#2>(T#2,T#2)int in interface MyComparable is generic)
where T#1,T#2 are type-variables:
T#1 extends Comparable<T#1> declared in method <T#1>sort(List<T#1>,MyComparable)
T#2 extends Comparable<T#2> declared in method <T#2>compare(T#2,T#2)
1 error


из этого сообщения об ошибке, похоже, что компилятор не может вывести аргументы типа. Это так? Если да, то почему это происходит так?



я пробовал разные способы, искал через интернет. Тогда я нашел это JavaCodeGeeks статья, который показывает путь, так что я пробовал:



sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));


который снова не работает, вопреки тому, что эта статья утверждает, что она работает. Возможно, что он работал в некоторых начальных сборках.



Итак, мой вопрос: есть ли способ, чтобы создать лямбда-выражение для универсального метода? Я могу сделать это с помощью ссылки на метод, хотя, создав метод:



public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}


в каком-то классе говорят SO, и передать его как:



sort(list, SO::compare);
570   4  

4 ответов:

вы не можете использовать лямбда-выражение на функционального интерфейса, если метод в функционального интерфейса и параметры типа. Смотрите раздел §15.27.3 в JLS8:

лямбда-выражение, совместимое [..] с целевым типом T Если T является функциональным типом интерфейса (§9.8) и выражение congruent С типом функции [..] Т. [..] Лямбда-выражение-это congruent С типом функции, если все следующие правда:

  • тип функции никаких параметров типа.
  • [..]

используя ссылку на метод, я нашел другой способ передать аргумент:

List<String> list = Arrays.asList("a", "b", "c");        
sort(list, Comparable::<String>compareTo);

Вы имеете в виду что-то вроде этого?:

<T,S>(T t, S s)->...

какого типа эта лямбда? Вы не можете выразить это в Java и поэтому не можете составить это выражение в приложении функции, а выражения должны быть составными.

для этого нужно будет работать вам понадобится поддержка Типы Rank2 в Java.

методы могут быть универсальными, но поэтому вы не можете использовать их в качестве выражений. Однако они могут быть сведены к лямбде выражение путем специализации всех необходимых универсальных типов, прежде чем вы сможете передать их: ClassName::<TypeName>methodName

просто укажите компилятору правильную версию универсального компаратора с помощью (Comparator<String>)

Так что ответ будет

sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));

Comments

    Ничего не найдено.