Suppose I've a generic interface:
interface MyComparable<T extends Comparable<T>> {
public int compare(T obj1, T obj2);
}
And a method sort
:
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}
I can invoke this method and pass a lambda expression as argument:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
That will work fine.
But now if I make the interface non-generic, and the method 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) {
}
And then invoke this like:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
It doesn't compile. It shows error at lambda expression saying:
"Target method is generic"
OK, when I compiled it using javac
, it shows following error:
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
From this error message, it seems like compiler is not able to infer the type arguments. Is that the case? If yes, then why is it happening like this?
I tried various ways, searched through the internet. Then I found this JavaCodeGeeks article, which shows a way, so I tried:
sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));
which again doesn't work, contrary to what that article claims that it works. Might be possible that it used to work in some initial builds.
So my question is: Is there any way to create lambda expression for a generic method? I can do this using a method reference though, by creating a method:
public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
in some class say SO
, and pass it as:
sort(list, SO::compare);
You can't use a lambda expression for a functional interface, if the method in the functional interface has type parameters. See section §15.27.3 in JLS8:
A lambda expression is compatible [..] with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of [..] T. [..] A lambda expression is congruent with a function type if all of the following are true:
- The function type has no type parameters.
- [..]