Supongamos que tengo una interfaz genérica:
interface MyComparable<T extends Comparable<T>> {
public int compare(T obj1, T obj2);
}
Y un método sort
:
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}
Puedo invocar este método y pasar una expresión lambda como argumento:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
Eso funcionará bien.
Pero ahora, si hago la interfaz no genérica y el método genérico:
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) {
}
Y luego invoca esto como:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
No se compila. Muestra un error en la expresión lambda que dice:
"El método de destino es genérico"
OK, cuando lo compilé usando javac
, muestra el siguiente 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
A partir de este mensaje de error, parece que el compilador no puede inferir los argumentos de tipo. ¿Es ese el caso? Si es así, ¿por qué está sucediendo así?
Probé de varias formas, busqué en Internet. Luego encontré este artículo de JavaCodeGeeks , que muestra una forma, así que probé:
sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));
que de nuevo no funciona, al contrario de lo que ese artículo afirma que funciona. Podría ser posible que solía funcionar en algunas versiones iniciales.
Entonces mi pregunta es: ¿hay alguna forma de crear una expresión lambda para un método genérico? Sin embargo, puedo hacer esto usando una referencia de método, creando un método:
public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
en alguna clase decir SO
, y pasarlo como:
sort(list, SO::compare);