Вопрос-ответ

Lambda Expression and generic defined only in method

Лямбда-выражение и generic, определенные только в методе

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

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));

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

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

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);
Переведено автоматически
Ответ 1

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


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



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

  • [..]


Ответ 2

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

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

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

Итак, ответ будет следующим

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

Ответ 4

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

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

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

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

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

java generics lambda java-8