Предположим, у меня есть общий интерфейс:
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);
Используя ссылку на метод, я нашел другой способ передать аргумент:
источник
Просто укажите компилятору правильную версию универсального компаратора с
(Comparator<String>)
Так что ответ будет
sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));
источник
incompatible types: java.util.Comparator<java.lang.String> cannot be converted to MyComparable
иMyComparable
не является универсальным (без типа), поэтому(MyComparable<String>)
тоже не будет работатьCompartor
?Вы имеете в виду что-то вроде этого?:
К какому типу относится эта лямбда? Вы не можете выразить это в Java и, следовательно, не можете составить это выражение в приложении-функции, а выражения должны быть составными.
Для этого вам понадобится поддержка типов Rank2 в Java.
Методы могут быть универсальными, но поэтому вы не можете использовать их как выражения. Однако их можно свести к лямбда-выражениям путем специализации всех необходимых универсальных типов, прежде чем вы сможете их передать:
ClassName::<TypeName>methodName
источник
"Of what type is this lambda? You couldn't express that in Java..."
Тип будет выводиться с использованием контекста, как и для любой другой лямбды. Тип лямбды явно не выражен в самой лямбде.