advanced - lambda expressions java 8 example
Lambda Expression y método genérico (2)
Supongamos que tengo una interfaz genérica:
interface MyComparable<T extends Comparable<T>> {
public int compare(T obj1, T obj2);
}
Y un método de 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 que la interfaz no sea 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 invocar esto como:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
No compila Muestra un error en la expresión lambda diciendo:
"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
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í?
Intenté 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 nuevamente no funciona, al contrario de lo que dice ese artículo que funciona. Podría ser posible que solía funcionar en algunas compilaciones iniciales.
Entonces mi pregunta es: ¿hay alguna forma de crear expresiones lambda para un método genérico? Sin embargo, puedo hacer esto usando una referencia de método, al crear 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);
No puede usar una expresión lambda para una interfaz funcional , si el método en la interfaz funcional tiene parámetros de tipo . Ver la sección §15.27.3 en JLS8 :
Una expresión lambda es compatible [...] con un tipo de destino T si T es un tipo de interfaz funcional (§9.8) y la expresión es congruente con el tipo de función de [..] T. [..] Una expresión lambda es congruente con un tipo de función si todos los siguientes son verdaderos:
- El tipo de función no tiene parámetros de tipo .
- [..]
Usando la referencia del método, encontré otra forma de pasar el argumento:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, Comparable::<String>compareTo);